home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-05-17 | 400.0 KB | 12,744 lines | [TEXT/MPS ] |
- /*
- File: LynxFWIM.c
-
- Contains: Sample code for FWIM for Texas Instruments PCI-Lynx (TSB12LV21A)
-
- Version: 1.0
-
- Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
-
- File Ownership:
-
- DRI: Eric Anderson
-
- Other Contact: Clinton Bauder
-
- Technology: FireWire
-
- Writers:
-
- (EA) Eric Anderson (ewa)
-
- Change History (most recent first):
-
- <FW3> 12/21/98 EA Copied in all the old check-in comments.
- <FW2> 12/21/98 EA Copied from branch <FW112a4> to main sources so we can build
- different.
- <FW1> 12/21/98 EA first checked in
- */
-
-
- /////// Old check-in comments.
- // <FW112a4> 9/4/98 DCB Updating from main project base.
- // <FW121> 9/3/98 CP Under certain conditions the isoch interrupt handling logic
- // could service an update or callproc twice in a row. We now look
- // if the last element of the previous queue is the first element
- // of the next queue and punt it if necessary.
- // <FW120> 9/1/98 DCB Per <EA> don't clear RHB or CycleMaster immediately on finalize.
- // Instead just clear Contender, shutdown the comparators and issue
- // a reset. Then wait for root holdoff bit to go away. If it
- // doesn't go away in say 100ms give up and just turn it off. We
- // should wait longer but it probably doesn't matter and much
- // longer will be noticeable during shutdown.
- // <FW119> 9/1/98 DCB Did two things. If a Read Request gets a link timeout then only
- // retry once. This reduces the traffic after a reset for nodes
- // that aren't responding. Second clear RHB, CycleMaster and
- // Contender before Finalizing the FWIM. Also issue a bus reset
- // after this so everybody knows we went away.
- // <FW118> 8/31/98 DCB Don't enable kLynxENA_POST_WR and kLynxENA_SLV_BURST since the
- // errata for Rev A parts advises NOT to do this anymore. Also
- // simplified the code when stopping a DCL program to just wait 2ms
- // rather than using unsafe register accesses to watch for the FIFO
- // to settle. Finally make the FWIM install correctly even if the
- // PHY is unpowered.
- // <FW116> 8/27/98 DCB Fixing the maximum packet size for s400. Also we now depend on
- // the buffers being allocated contiguously since they don't divide
- // into page size anymore.
- // <FW115> 8/25/98 DCB Re-work the way we decide whether to load the FWIM based on PHY
- // power state so we don't have any timers outstanding nor do we
- // tell FSL about a reset on a FWIM that doesn't exist yet.
- // <FW114> 8/24/98 EA Added dispatch for FWGetCycleTime.
- // <FW112a3> 8/4/98 jkl Remove unnecessary include files.
- // <FW112a2> 7/24/98 DCB Roll in Eric's VM fix from the main sources.
- // <FW113> 7/24/98 DCB <EA> Fix an off-by-one™ error in the calculation of
- // pLynxFWIMData->pageShift which was causing some
- // PrepareMemoryForIO problems with VM on.
- // <FW112a1> 7/20/98 DCB Cleaned up this file for the SDK release.
- // <FW112> 7/17/98 DCB Added LynxFWIMSetFWIMState. This new API allows us to put FWIMs
- // to sleep. This can be for the purpose of saving power or to
- // "quiesce" the FWIM so it won't bother the FSL while the FSL is
- // being replaced or fovr'd. Right now the call is pretty heavy
- // handed and does a full reset when we go active again. This may
- // not be necessary but I haven't thought it through enough yet.
- // Meantime this will allow me to experiment with fovr'ing.
- // <FW111> 7/15/98 DCB Found the memory leak. Things allocated with
- // MemAllocatePhysicallyContiguous need to be deallocated with
- // MemDeallocatePhysicallyContiguous not PoolDeallocate.
- // <FW110> 7/14/98 DCB Implemented LynxFWIMFinalize which will be needed when we start
- // replacing FWIMs that were in "ROM" from an extension. There's
- // still some work to do as I've noticed a few memory leaks, but
- // its mostly there. I'll track down the leaks tomorrow.
- // <FW109> 7/13/98 EA Changed to process local self ID from FujiFilm MF8404 PHY on
- // some cards. Also made hardware power class depend on compile- time
- // options.
- // <FW108> 7/8/98 DCB Made the FWIM more PCI-PCI bridge friendly be only reporting
- // kIsrIsComplete from our interrupt handler if indeed we saw an
- // interrupt. Otherwise we return kIsrIsNotComplete so sources
- // further down the tree don't get starved. There are still some
- // issues with interrupt polling which I don't know how to fix yet.
- // Stay tuned.
- // <FW106> 7/7/98 DCB When getting the new node ID from the PHY we were endian
- // swapping the damn thing once too many times. This led to well
- // random node IDs which is, well, bad.
- // <FW105> 7/7/98 DCB Cleaned up error reporting back to FSL. We no longer pay
- // attention to the errors returned from FWIMCommandIsComplete and
- // instead always return the same error reported to
- // FWIMCommandIsComplete. The returned error is only used for
- // immediate calls anyway but for consistency we should always
- // report the same thing sent from FWIMCommandIsComplete.
- // <FW104> 7/5/98 EA Add example of using csrROMUpdateInProgress during SetCSRROM.
- // Added new feature info during initialize, including OpenHCI
- // features and power features. Add other new dispatch table
- // entries as sample code. Removed first-time bus reset during
- // install.
- // <FW103> 7/1/98 EA Add dispatch entry for FWSetCSRROM, as an example for OpenHCI.
- // <FW101> 7/1/98 DCB Changed the parameters to LynxFWIMBuildAsyncTxPCL so that we
- // pass in the ioPreparationTable instead of allocating it on the
- // stack inside the function. CheckpointIO needs this structure and
- // we don't call it til after we leave the function. As a result
- // the table (which was on the stack) was no longer valid and we
- // crashed. Also added some debugging info to keep track of the
- // last 4 interrupts.
- // <FW100> 6/25/98 DCB Three changes. First clear pLynxFWIMData->pNextAsyncPCL in
- // LynxFWIMFullReset so we correctly process incoming packets
- // immediately instead of having to wait til we cycled through the
- // list of PCLs. This way we wake up much quicker when the PHY
- // becomes powered again. Second, delayed the reset after waking up
- // the from PHY sleep to be more friendly. Third, got rid of the
- // check for the transmitter becoming disabled when sync-wait for
- // TX requests. The required register wasn't PHY safe so accessing
- // it depended on the safe register access code which uses the TX
- // channel. Now we just wait for the 50ms timeout to occur.
- // <FW99> 6/23/98 DCB The G3 problem turned out to be a speed issue. Apparently if you
- // hit one of the "safe" registers quickly enough after the part
- // stopped DMA because the PHY wasn't powered the Link generates a
- // target abort. Grrr. Now we wait (an arbitrary) 25 microseconds
- // before checking to see if the DMA stopped. Also fixed a rare but
- // real uninitialized variable problem in LynxFWIMSafeRegisterRead.
- // <FW98> 6/23/98 DCB Made some progress on the safe register access front. We need to
- // protect 0xA00 space registers too. Also, when we fail an access
- // now we cancel the current transaction and return errors from
- // subsequent commands until things look better. Every 5 seconds we
- // try to reset everthing to see whether we have power. There are
- // still at least 3 issues. First, it doesn't work on G3s. Second,
- // the PHY needs to be powered during FWIM initialization or we
- // won't load it. Finally, there are a couple of 0xA00 registers
- // that apparently can't be accessed with DMA. I'm looking into
- // just not using these registers but for now we assume if the PHY
- // was powered just a few instructions ago it still is now.
- // <FW97> 6/15/98 DCB Fixed two things. Most importantly fixed a silly logical vs
- // physical bug in LynxFWIMSafeRegisterRead which prevented us from
- // working on some machines. Also fixed some cleanup code if we
- // fail to allocate an isochronous channel and have to de-allocate
- // it immediately.
- // <FW96> 6/5/98 DCB All registers above 0xB00 are now accessed with DMA rather than
- // the memory map. This doesn't make the world safe for unpowered
- // PHYs just yet, however. Now I have to figure out what to do when
- // an access fails. We have to return all outstanding requests,
- // shutdown any isoch channels and wait somehow for things to get
- // better.
- // <FW95> 6/4/98 DCB Check in early, check in often... I'm done with the linkControl
- // register and busNumberNodeNumber. I'm tired and want to go home
- // so for now I'll check this in and get the rest of the registers
- // tomorrow.
- // <FW94> 6/2/98 DCB Check in early, check in often... Use the safe register access
- // routines when playing with the comparator registers. No action
- // yet if the routines fail. Other registers above 0xB00 are up
- // next.
- // <FW93> 5/21/98 DCB Fixed up LynxFWIMWaitAsyncTXFree to make it more readable.
- // Instead of having a complicated "stop" scheme which works under
- // all conditions we now pass in a set of conditions to wait for.
- // <FW92> 5/21/98 DCB Mostly finished writing the "Safe Register Access" routines that
- // use DMA to access the Lynx registers above 0xB00. These are
- // needed because if the PHY is unpowered accesses to these
- // registers will bus error. Next I have to try and use them for
- // something more than the PHYPowerCheck. After that I have to
- // write the code that sleeps the FWIM until the PHY is powered
- // again.
- // <FW91> 5/18/98 DCB Re-work the interrupt enablers and disablers to make them safe
- // for use with PCI-PCI bridges. Basically we turn them off at the
- // chip now rather than use the default enablers. Otherwise we can
- // end up with a spurious interrupt if we're disabled but the
- // hardware causes an interrupt.
- // <FW90> 5/12/98 DCB Fix the version number. Why do they keep changing the spelling
- // of these constants?
- // <FW89> 5/12/98 DCB Fixing up the PHY Reg Received stuff to plug a hole where we
- // might not ever re-enable the receiver. Now we set a timer and if
- // we don't get anymore resets after a while we turn the receiver
- // on. The timer protects itself from further resets by keeping the
- // comparators turned off.
- // <FW78a7> 4/21/98 DCB Added support for 1394-1995 style PHYs with >3 ports.
- // <FW78a6> 4/20/98 DCB Set speed to 400MBit if appropriate on XMit.
- // <FW78a5> 4/7/98 DCB Cleaned up the PhyPowerCheck code a bit.
- // <FW78a4> 4/6/98 DCB Also fixed some stupid mistakes with the placement of the disable
- // user code calls.
- // <FW88> 4/8/98 jkl Changed build stage in driver descriptor to final.
- // <FW87> 4/3/98 DCB Whoops, one minor bug in the last checkin. Checked the wrong ptr
- // before disposing of allocated memory.
- // <FW86> 4/2/98 DCB Fix PhyPowerCheck to work when logical != physical (ie when VM
- // is turned on or you are running on a Pex or Columbus machine.
- // <FW78a3> 3/24/98 DCB Rollins from TOT.
- // <FW85> 3/24/98 jkl Removed DebugStrs in PhyPowerCheck code.
- // <FW84> 3/24/98 jkl Added PhyPowerCheck routine using DMA to read the
- // busNumberNodeNumber register.
- // <FW78a2> 3/23/98 DCB Allow more flexibility for assignments of DMA channels so we can
- // use 3 for whatever combination of isochronous Xmit and Rcv we
- // want. Also now don't run the SIH queues from the interrupt poll
- // proc if we have marked ourselves busy. Many of the SIHs need to
- // be synchronized and don't like re-entrancy.
- // <FW83> 3/9/98 jkl Changed error returned by AllocateIsochPort to paramErr per
- // documentation.
- // <FW82> 3/9/98 DCB Adding support for TSB41LV06 PHY. Where apporpriate use extended
- // PHY register set. Use self-id packet from bus rather than PHY
- // registers. Set/Clear contender bit with PHY registers rather
- // that GPIO if we have extended register set. Support 6 ports. Fix
- // a race condition in self-id processing for both old and new
- // PHYs.
- // <FW81> 2/25/98 jkl Removed bus reset holdoff. Causing problems with multiple machines.
- // <FW80> 2/25/98 jkl Correct inUse flag problem with bus reset request holdoff.
- // <FW79> 2/24/98 jkl Restore all previous changes except for ATF. Fix WriteATF
- // Subtract routine so we actually wait a millisecond between each
- // register read. Changed the bus reset request holdoff to be
- // execution level safe. Five reset requests can be held, after
- // that they return timeout error.
- // <78a1> 2/19/98 DCB Added lots of Enable and DisableVMUserCode calls so we work
- // better as part of the backing store path. Fixed up the way we do
- // interrupt polling so it actually works. Conditionalized this
- // stuff so it doesn't break anything. Added some debug logging
- // stuff as well.
- // <78> 2/6/98 jkl Backed out previous atf changes. Modified WriteATF to wait for
- // much longer time before busying out. Fixes Panasonic camera
- // problem. Added #ifdefs to build various versions of
- // LynxLiteFWIM.
- // <77> 2/1/98 jkl Work on some FWIM updates: - unsafe resize FIFO code, pause
- // asynch receiver - make the writeATF routine asynchronous -
- // report the true power class - hold off reset requests for two
- // seconds after receiving a reset - fix the start immediate option
- // for isoch receive - AllocateLocalIsochronousPort should return
- // an error if port is in use
- // <FW76> 5/28/97 EA Fixed rare case where FWIM jams because an unexpected "special
- // ack" from Lynx leaves us in limbo.
- // <FW75> 4/1/97 EA Fixed recovery from async receive overflow by turning comparator
- // back on after DMA is restarted.
- // <FW74> 3/18/97 ES Changed driver description version to final.
- // <FW73> 3/10/97 EA Added support for ReceivePacketOp. Removed possibly dangerous
- // debug messages from primary interrupt handlers.
- // <FW72> 3/10/97 ES Changed LynxFWIMUpdateDCLTimeStamp to add one cycle to
- // compensate for work ahead. Increased maximum number of
- // simultaneous queued interrupts to 100.
- // <FW71> 3/6/97 EA Changed ISO TX stop mechanism to eliminate aux commands and
- // double PCLs, to reduce PCI latencies. Stop now uses check on
- // ready bit before each packet. Also fixed GRF-jam recovery to
- // actually work.
- // <FW70> 3/5/97 EA Changed to disable CYCMASTER faster (in primary interrupt
- // handler) if we are no longer root after a bus reset, to reduce
- // PHY jams. Added recovery mechanism for rare GRF-jam problem.
- // <FW69> 3/3/97 ES Added support for DCLTimeStamp.
- // <FW68> 2/27/97 EA Made changes to try to reduce vulnerability to PHY jams by
- // eliminating redundant bus resets.
- // <FW67> 2/18/97 EA Changed how we send acks, and how we react to acks. Changed
- // reset processing of new node ID. Added a bunch of comments about
- // acks. Also removed LED-blinking code.
- // <FW66> 2/14/97 ES Added LynxFWIMFinalize and LynxFWIMPollInterrupts to plug in
- // dispatch table.
- // <FW65> 2/14/97 ES Changed to mask out DCL opcode flags.
- // <FW64> 2/13/97 EA Commented out #define LynxFireBug for safety.
- // <FW63> 2/12/97 EA Changed transmit DMA to not hammer Lynx while waiting.
- // <FW62> 2/11/97 EA Added CRC-16 check of serial EEPROM contents.
- // <FW61> 2/7/97 EA Temporary hack to LynxFWIMGetRegisterBaseAddress
- // <FW60> 2/6/97 EA Added routines to load serial EEPROM to find global unique ID
- // and other HW config info.
- // <FW59> 2/6/97 ES Removed use of status field in FWIMCommandParams record.
- // <FW58> 2/4/97 ES Changed LynxFWIMCreateAsyncTxDonePCLSegment to use logical lynx
- // fwim data pointer instead of physical pointer when manually
- // setting asyncTxDoneFlag.
- // <FW57> 1/29/97 ES Fixed implied return warning in LynxFWIMWriteTimer.
- // <FW56> 1/29/97 ES Added check for internal DMA transmit errors to
- // LynxFWIMAckSecondaryInterruptHandler. Will schedule a transmit
- // retry 10ms after detecting error.
- // <FW55> 1/17/97 EA Fixed AT DMA hang due to TX disable from bus reset during
- // transmit
- // <FW54> 1/15/97 EA Fixed Open Firmware/Assigned-address matching bug
- // <FW53> 1/9/97 ES Changed LynxFWIMWriteATF to not explicitly start transmit DMA.
- // This is done in LynxFWIMAddAsyncTxPCL and was causing DMA
- // transmit problems.
- // <FW52> 1/1/97 ES Added support for updating DCL commands. Added support for
- // servicing more than one isoch interrupt at a time.
- // <FW51> 12/26/96 ES Changed to use DCL program stop and release routines.
- // <FW50> 12/20/96 ES Cleaned up LynxFWIMWriteATF.
- // <FW49> 12/18/96 ES Changed GRF overflow handling to not flush GRF.
- // <FW48> 12/26/96 ES Consolidated some parameters in asynch FWIM commands and
- // processing.
- // <FW47> 12/22/96 ES Changed IsochPortAction to IsochPortControl.
- // <FW46> 12/12/96 ES Took transmit buffer out of FWIMProcessAsynchParams record.
- // <FW45> 12/6/96 ES Changed FWIMInstallParams to FWIMInitializeParams and changed
- // some of the fields in FWIMInitializeParams. Changed
- // LynxFWIMInstall to LynxFWIMInitialize. FWIMAsynchCommandParams
- // were changed to supply the split transaction timeout.
- // <FW44> 12/6/96 ES Changed the process read and lock response packet routines to
- // return an error if the response code indicates an error.
- // <FW43> 12/6/96 ES Fixed a write to nil bug in LynxFWIMCompileDCLProgram.
- // <FW42> 11/26/96 ES Changed to use FWSetDCLProgramStartProc.
- // <FW41> 11/26/96 ES Changed LynxFWIMWriteATF to wait 100000 times. Changed
- // LynxFWIMStartAsyncRxPCLProgram to wait for a fixed number of
- // PCLs to become available before restarting the receive DMA.
- // <FW40> 11/11/96 ES Added LynxFWIMGetUniqueID.
- // <FW39> 11/9/96 ES Changed async receive mechanism. Async receive is disabled once
- // we've used all the PCLs. PCLs are dynamically added back into
- // the async receive program as they are freed.
- // <FW38> 11/5/96 ES Changed to use FireWire deferred tasks instead of secondary
- // interrupts.
- // <FW37> 11/5/96 ES Fixed GRF overflow bug when stopping isoch receiving.
- // <FW36> 10/27/96 EA Fixed my checkin initials (D'oh!)
- // <FW35> 10/27/96 EA Added support for VM everywhere. Also added a lot of comments
- // <FW34> 10/18/96 ES Expanded DCL compiler notification proc. Added call to
- // FWStartDCLProgram in LynxFWIMStartIsochPort.
- // <FW33> 10/4/96 ES Changed to use FWCallDCLCallProc.
- // <FW32> 10/4/96 ES Replaced DCLSetPacketAttributes with DCLSetTagSyncBits and added
- // DCLSendPacketWithHeaderStart.
- // <FW31> 10/3/96 ES Changed to use FWIMPluginDispatchTable.
- // <FW30> 10/3/96 ES Got rid of LynxFWIMGetTopologyMap. We now call FWProcessSelfIDs.
- // Tried to reduce problems with overflowing the ASYNC ring buffer.
- // <FW29> 10/2/96 ES Changed interrupt handling to only queue one secondary interrupt
- // handler at a time per interrupt source.
- // <FW28> 9/25/96 ES Added asynchronous transaction response FWIM commands. Changed
- // the way asynchronous requests are processed and responded to.
- // <FW27> 9/16/96 ES Took out some read response and isoch continue stuff.
- // <FW26> 9/16/96 ES Changed FWIM interface to return command acceptance.
- // <FW25> 9/16/96 ES Changed to use response code returned from
- // FWProcessRead/Write/LockRequest.
- // <FW24> 9/11/96 ES Changed to use speed parameter passed in to asynchronous FWIM
- // calls and to properly set local speed bits in topology map.
- // <FW23> 9/5/96 ES Changed to call FWProcessRead/Write/LockRequest asynchronously.
- // <FW22> 9/3/96 ES Added interface to send out link on packets.
- // <FW21> 8/30/96 ES Added enable/disable cycle master, set/clear root holdoff bit,
- // send phy configuration packet, and other stuff to support
- // isochronous resource management.
- // <FW20> 8/29/96 ES Added capability to set and clear contender bit and to
- // accurately report state of contender bit in topology map. Also
- // added support for handling lock requests.
- // <FW19> 8/27/96 ES Fixed a bug in LynxFWIMGetTopologyMap.
- // <FW18> 8/26/96 ES Conditionalize DebugStrs on FWDebugBuild.
- // <FW17> 8/26/96 ES Changed LynxFWIMGetTopologyMap to return local node ID.
- // <FW16> 8/19/96 ES Changed to use separate interrupt pDCLCallProc for each pcl
- // program. Also changed to clear pDCLCallProc after it's been
- // handled.
- // <FW15> 8/16/96 ES Implemented hack to treat ack pending as ack complete for
- // sending write requests to fix mass storage driver. Also changed
- // stop isoch port to immediately set channel inactive for receive.
- // <FW14> 8/16/96 ES Changed LynxFWIMReleaseIsochPort to pass status in to
- // FWIMCommandIsComplete.
- // <FW13> 8/15/96 ES Added compiler notificaton proc for DCL programs. Also added
- // support for dynamically changing the destination of DCL jumps.
- // <FW12> 8/8/96 ES Improved error handling for allocating isochronous ports. Will
- // now deallocate isoch port PCLs.
- // <FW11> 8/8/96 ES Changed to use DCL translation services.
- // <FW10> 8/7/96 ES Added option to build driver description for Lynx Lite.
- // <FW9> 8/2/96 ES Updated for more isochronous changes.
- // <FW8> 8/1/96 ES Took out unused local variables.
- // <FW7> 7/31/96 ES Changed to use new isochronous buffer architecture.
- // <FW6> 7/11/96 ES Added dynamic FIFO allocation for isochronous transmission and
- // changed to handle ITF underflow better.
- // <FW5> 7/8/96 ES Added isoch transmit capability. Still need to work out FIFO
- // sizing.
- // <FW4> 7/2/96 EA Made all DMA and PCLs cache-aligned, fixed
- // cycle-master behavior, fixed DMA jam, fixed FIFO
- // thresholds, etc.
- // <FW3> 6/20/96 ES Changed some comments.
- // <FW2> 6/12/96 EA Fill in contains and written by fields.
- // <FW1> 6/12/96 EA first checked in
- ///////
-
-
- // This was adapted from Erik's TIFWIM, long ago.
-
- // TIP FOR BEST PERFORMANCE
- // Avoid touching Lynx registers. Lynx may be in the middle of a DMA when you
- // do so, and it has to suspend that while it answers your query. This leads
- // to FIFO underflows and overflows. So touch registers only when there's no
- // other choice. [Note: do as we say, not as we do.]
-
- //#define DebugStr(x) strlen(x)
-
-
- #include <Types.h>
- #include <Errors.h>
- #include <Devices.h>
- #include <Interrupts.h>
- #include <PCI.h>
- #include <DriverServices.h>
- #include <FireWire.h>
- #include <LynxFWIM.h>
- /*zzz*/
- #include <stdio.h>
- char debugStr[256];
- pascal void FWDebugStr(
- ConstStr255Param debuggerMsg)
- {
- #ifdef FW_DEBUG_BUILD
- #if FW_DEBUG_BUILD
- DebugStr (debuggerMsg);
- #endif
- #endif
- }
- /*zzz*/
-
- // Define this to check for Logical != Physical (use with VM off)
- //#define LynxVMDebug
-
- // Define this to enable sending diagnostic messages to FireBug
- //#define LynxFireBug
-
- #ifdef LynxFireBug
- char fireBug[256];
- #endif
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Hardware-dependent definitions. All of the power values are guesses.
- //
-
- #ifdef LynxLiteFWIM
- #if LynxLiteFWIM
- #define PCINameProperty "\ppci104c,8003"
- #define HardwareDeciWatts 60
- #define HardwareMinDeciVolts 110
- #define HardwareMaxDeciVolts 120
- #define HardwarePowerClass kFWSelfIDBusPowered1W
- #endif
- #endif
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Internal procedure prototypes.
- //
-
- static OSStatus LynxFWIMInitialize (
- FWIMInitializeParamsPtr pFWIMInitializeParams);
-
- static SInt32 LynxAllocateDMAChannel(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxDeAllocateDMAChannel(
- LynxFWIMDataPtr pLynxFWIMData,
- SInt32 dmaChannelNum);
-
- static OSStatus LynxFWIMFinalize (
- FWIMFinalizeParamsPtr pFWIMFinalizeParams);
-
- static OSStatus LynxFWIMPollInterrupts (
- FWIMPollInterruptsParamsPtr pFWIMPollInterruptsParams);
-
- static OSStatus LynxFWIMGetRegisterBaseAddress (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static OSStatus LynxFWIMInstallInterruptHandler (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static UInt16 LynxFWIMcrc16(
- UInt32 *data,
- UInt32 count);
-
- static void LynxFWIMControlEEPROM(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 clock,
- UInt32 data,
- UInt32 timer);
-
- static UInt32 LynxFWIMWaitForEEPROM(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMSendEEPROMBit(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 bit);
-
- static void LynxFWIMSendEEPROMByte(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 sendByte);
-
- static UInt32 LynxFWIMReadEEPROMBit(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static UInt8 LynxFWIMReadEEPROMByte(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMStartEEPROM (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMStopEEPROM (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMProcessEEPROM(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMFullReset(void);
-
- static OSStatus LynxFWIMExceptionHandler (
- ExceptionInformationPowerPC *theException);
-
- static InterruptMemberNumber LynxFWIMInterruptHandler (
- InterruptSetMember interruptSet,
- void *interruptRefCon,
- UInt32 interruptCount);
-
- static InterruptSourceState LynxFWIMInterruptDisabler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon );
-
- static void LynxFWIMInterruptEnabler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon );
-
- static Boolean LynxFWIMDispatchInterrupts (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMHandleDMAInterrupt(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 dmaChannel );
-
- static void LynxFWIMHandleLinkInterrupt (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMHandleResetInterrupt (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMHandlePhyRegRcvdInterrupt (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 interrupt);
-
- static void LynxFWIMHandleMiscInterrupt(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static OSStatus LynxFWIMResetBus (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMSetContenderBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMClearContenderBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMEnableCycleMaster (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMDisableCycleMaster (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMSetRootHoldoffBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMClearRootHoldoffBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMGetUniqueID (
- FWIMGetUniqueIDParamsPtr pFWIMGetUniqueIDParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMSendLinkOnPacket (
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMSendPhyConfigurationPacket (
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMSetCSRROM(
- FWIMSetCSRROMParamsPtr pFWIMSetCSRROMParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMDoLocalCompareSwap(
- FWIMCompareSwapParamsPtr pFWIMCompareSwapParams);
-
- static OSStatus LynxFWIMSetAsynchFilters(
- FWIMSetAsynchFiltersParamsPtr pFWIMSetAsynchFiltersParams);
-
- static OSStatus LynxFWIMSetFWIMState(
- FWIMSetFWIMStateParamsPtr pFWIMSetFWIMStateParams);
-
- static OSStatus LynxFWIMGetCycleTime(
- FWIMGetCycleTimeParamsPtr pFWIMGetCycleTimeParams);
-
- static void LynxFWIMWritePhyRegister (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 regAddress,
- UInt8 regData);
-
- static UInt8 LynxFWIMReadPhyRegister (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 regAddress);
-
- static void LynxFWIMPrepareAsyncDMA(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 channel);
-
- static void LynxFWIMAddAsyncRxPCL (
- LynxPCLPtr pPCL);
-
- static void LynxFWIMCreateAsyncRxPCLProgram (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMCreateAsyncRxDummyPCL (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMCreateAsyncRxOverflowPCLSegment (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMStartAsyncRxPCLProgram (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pStartPCL);
-
- static void LynxFWIMAddAsyncTxPCL (
- LynxPCLPtr pPCL);
-
- static void LynxFWIMCreateAsyncTxDummyPCL (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMCreateAsyncTxDonePCLSegment (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMCreateAsyncTxDataPCL (
- LynxFWIMDataPtr pLynxFWIMData);
-
- static void LynxFWIMStartAsyncTxPCLProgram (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pStartPCL);
-
- static OSStatus LynxFWIMSafeRegisterRead(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 * registerData );
-
- static OSStatus LynxFWIMSafeRegisterWrite(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData );
-
- static OSStatus LynxFWIMSetRegisterBits(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData );
-
- static OSStatus LynxFWIMClearRegisterBits(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData );
-
- static OSStatus LynxFWIMWaitAsyncTXFree(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 dmaChannel,
- UInt32 * waitFlag,
- UInt32 waitValue );
-
- static OSStatus LynxFWIMSetLinkControl (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl);
-
- static OSStatus LynxFWIMSetLinkControlBits (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl);
-
- static OSStatus LynxFWIMClearLinkControlBits (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl);
-
- static void LynxFWIMSetAsyncRxComparatorMask1 (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 mask1);
-
- static OSStatus LynxFWIMWriteATF(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 transmitType,
- UInt32 speed,
- UInt32 baseCount,
- UInt32 data1,
- UInt32 data2,
- UInt32 data3,
- UInt32 data4,
- UInt32 extCount,
- UInt32 *extData);
-
- static OSStatus LynxFWIMBuildAsyncTxPCL (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- IOPreparationTable *ioPreparationTable,
- UInt32 pclControl,
- Ptr buffer1,
- UInt32 size1,
- Ptr buffer2,
- UInt32 size2);
-
- static OSStatus LynxFWIMRead (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMReadResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMWriteTimer (
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMWrite (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMWriteResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMLock (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMLockResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static Boolean LynxFWIMIsCompilableDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMCompileDCLProgram (
- LynxFWIMDataPtr pLynxFWIMData,
- DCLProgramID dclProgramID,
- UInt32 pclChannelNum,
- UInt32 channelNum,
- UInt32 speed);
-
- static OSStatus LynxFWIMAddDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddReceivePacketStartDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddReceivePacketDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddSendPacketStartDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddSendPacketDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddCallProcDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddJumpDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMUpdateDCLListDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMTimeStampDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMPCLStart (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLBuildStatePtr *ppLynxPCLBuildState,
- LynxPCLPtr *ppPCL);
-
- static OSStatus LynxFWIMAddLabelDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMAddSetTagSyncBitsDCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMPCLAllocateWord (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 **ppWord);
-
- static OSStatus LynxFWIMPCLNew (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon);
-
- static OSStatus LynxFWIMPCLNewIsochReceive (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon,
- UInt32 speed);
-
- static OSStatus LynxFWIMPCLNewIsochTransmit (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon,
- UInt32 speed);
-
- static OSStatus LynxFWIMPCLExtend (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 pclType);
-
- static OSStatus LynxFWIMPCLLoadTemp (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pSource);
-
- static OSStatus LynxFWIMPCLStoreTemp (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest);
-
- static OSStatus LynxFWIMPCLStore0 (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest);
-
- static OSStatus LynxFWIMPCLStore1 (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest);
-
- static OSStatus LynxFWIMPCLCompareTemp16WithMask (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt16 compareValue,
- UInt16 compareMask);
-
- static OSStatus LynxFWIMPCLBranchIfEqual (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel);
-
- static OSStatus LynxFWIMPCLJump (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel,
- Ptr *ppPCLCommand);
-
- static OSStatus LynxFWIMPCLInterrupt (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand,
- Ptr *ppPCLCommand);
-
- static OSStatus LynxFWIMPCLAuxCommand (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 auxCommand,
- UInt32 waitBranchCondition,
- UInt32 auxParam);
-
- static OSStatus LynxFWIMPCLAddTransferBuffer (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr buffer,
- UInt32 bufferSize,
- Ptr *ppPCLCommand,
- UInt32 bufferAddrType);
-
- static OSStatus LynxFWIMResolveDCLLabel (
- DCLLabelPtr pDCLLabel);
-
- static LynxPCLPtr LynxFWIMGetDCLLabelPCLPtr (
- DCLLabelPtr pDCLLabel);
-
- static OSStatus LynxFWIMPCLLabel (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel);
-
- static LynxPCLPtr LynxFWIMGetPCLFromDCL (
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMDCLCompilerNotification (
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus LynxFWIMDCLCompilerUpdateNotification (
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus LynxFWIMUpdateDCLTimeStamp (
- DCLCommandPtr pDCLCommand);
-
- static OSStatus LynxFWIMDCLCompilerModifyNotification (
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus LynxFWIMAllocatePCLBuildState (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLBuildStatePtr *ppLynxPCLBuildState);
-
- static OSStatus LynxFWIMAllocatePCL (
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL);
-
- static void LynxFWIMDeallocatePCLPools (
- LynxPCLPoolDataPtr pLynxPCLPoolDataList);
-
- static void LynxFWIMRunDCLProgram (
- LynxIsochPortDataPtr pLynxIsochPortData,
- Ptr packetBuffer,
- UInt32 packetSize,
- DCLCommandPtr *ppDCLCommand);
-
- static void LynxFWIMDCLReceivePacketStart (
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket);
-
- static void LynxFWIMDCLReceiveBuffer (
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket);
-
- static OSStatus LynxFWIMAllocateIsochPort (
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMReleaseIsochPort (
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus _LynxFWIMReleaseIsochPort (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxIsochPortDataPtr pLynxIsochPortData);
-
- static OSStatus LynxFWIMStartIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMStopIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus LynxFWIMStartTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMStartListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMStopTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMStopListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMReleaseDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus LynxFWIMReadRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMWriteRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMLockRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static void LynxFWIMDeferredTaskMultiplexer(
- void *p1,
- void *p2);
-
- static void LynxFWIMDMAAsyncPCLDeferredTask(
- void *p1,
- void *p2);
-
-
- static void LynxFWIMDMAIsochReceivePCLDeferredTask(
- void *p1,
- void *p2);
-
- static void LynxFWIMDMAIsochTransmitDeferredTask(
- void *p1,
- void *p2);
-
- static void LynxFWIMResetDeferredTask (
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMDelayedReset(
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMDelayedPhyRegReceived(
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMHoldoffResetRequests(
- void *p1,
- void *p2);
-
- static void LynxFWIMMiscInterruptDeferredTask (
- void *p1,
- void *p2);
-
- static OSStatus LynxFWIMAckSecondaryInterruptHandler (
- void *p1,
- void *p2);
-
- static void LynxFWIMInformFSLofSelfIDs(
- LynxFWIMDataPtr pLynxFWIMData );
-
- static void LynxFWIMProcessPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessSelfIDPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessWriteQuadletPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessWriteQuadletRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void LynxFWIMProcessWriteBlockPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessWriteBlockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void LynxFWIMProcessWriteResponsePacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessReadQuadletPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessReadQuadletRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void LynxFWIMProcessReadBlockPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessReadBlockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void LynxFWIMProcessReadQuadletResponsePacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessReadBlockResponsePacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessLockPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessLockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void LynxFWIMProcessIsochronousBlockPacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMProcessLockResponsePacket (
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void LynxFWIMSetupFIFOs (
- LynxFWIMDataPtr pLynxFWIMData);
-
- void LynxFWIMInterruptSetup(
- LynxFWIMDataPtr pLynxFWIMData);
-
- void LynxFWIMDisableVMUserCode(
- LynxFWIMDataPtr pLynxFWIMData);
-
- void LynxFWIMEnableVMUserCode(
- LynxFWIMDataPtr pLynxFWIMData);
-
- static OSStatus LynxFWIMDisableComparators (
- LynxFWIMDataPtr pLynxFWIMData );
-
- static OSStatus LynxFWIMEnableComparators (
- LynxFWIMDataPtr pLynxFWIMData );
-
- void LynxFWIMWaitForPHYPower(
- LynxFWIMDataPtr pLynxFWIMData,
- Boolean sleepRequest);
-
- static OSStatus LynxFWIMAttemptPHYWakeup(
- void *p1,
- void *p2);
-
- #ifdef LynxFireBug
- static void LynxFWIMFireBugMsg (
- LynxFWIMDataPtr pLynxFWIMData,
- char *msg);
- #endif
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The driver descriptor.
- //
-
- DriverDescription TheDriverDescription =
- {
- kTheDescriptionSignature,
- kInitialDriverDescriptor,
- {
- PCINameProperty, // This is a macro defined at the top of this file
- 1, 1, developStage, 2,
- },
- {
- kDriverIsUnderExpertControl,
- "\pAppleFWIM",
- },
-
- 1,
- kServiceCategoryFWIM,
- 0,
- 1,0,0,0
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The plug in dispatch table.
- //
-
- FWIMPluginDispatchTable ThePluginDispatchTable =
- {
- kFWIMPluginVersion11,
- LynxFWIMInitialize,
- LynxFWIMFinalize,
- LynxFWIMPollInterrupts,
- LynxFWIMSendLinkOnPacket,
- LynxFWIMSendPhyConfigurationPacket,
- LynxFWIMRead,
- LynxFWIMReadResponse,
- LynxFWIMWrite,
- LynxFWIMWriteResponse,
- LynxFWIMLock,
- LynxFWIMLockResponse,
- LynxFWIMAllocateIsochPort,
- LynxFWIMReleaseIsochPort,
- LynxFWIMStartIsochPort,
- LynxFWIMStopIsochPort,
- LynxFWIMResetBus,
- LynxFWIMSetContenderBit,
- LynxFWIMClearContenderBit,
- LynxFWIMEnableCycleMaster,
- LynxFWIMDisableCycleMaster,
- LynxFWIMSetRootHoldoffBit,
- LynxFWIMClearRootHoldoffBit,
- LynxFWIMGetUniqueID,
- LynxFWIMSetCSRROM,
- LynxFWIMDoLocalCompareSwap,
- LynxFWIMSetAsynchFilters,
- LynxFWIMSetFWIMState,
- LynxFWIMGetCycleTime
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInitialize
- //
- // This is the FWIM installer proc. It allocates the FWIM data record, gets
- // the register base address, installs the interrupt handler, enables the
- // register memory space, sets the chip up to receive selfID packets,
- // enables bus reset interrupts, and initiates a bus reset to get the topology
- // map.
- //zzz Clean up on error???
- //zzz Do we always need to initiate a bus reset???
- //
-
- // Ugly - right now, LynxFWIMFullReset is called from some places where this value isn't available
- static LynxFWIMDataPtr HACKdata;
- static UInt32 NoPhyReset = 0;
-
- static OSStatus LynxFWIMInitialize(
- FWIMInitializeParamsPtr pFWIMInitializeParams)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- RegEntryIDPtr pFWIMRegEntryID;
- Ptr p,p1;
- IOPreparationTable *ioPrep;
- UInt32 pageSize, totalAlloc;
- UInt32 bufPages;
- UInt32 pclsPerPage, pclPages;
- UInt32 doBuf, offset;
- Ptr logPage, physPage;
- OSStatus status = noErr;
- UInt32 dmaChannelNum;
-
- //DebugStr("\pStep twice and set r0=0 to load FWIM");
- //if( pFWIMInitializeParams->fwimSpecificData )
- // return (-1);
-
- // Set our features. This is for Lynx:
- pFWIMInitializeParams->fwimFeatures = kFWIMSetFWIMState; // Knows how to go to sleep
- pFWIMInitializeParams->fwimCSRROMMapLength = 0;
-
- // OpenHCI 1.0 would do this:
- //pFWIMInitializeParams->fwimFeatures = kFWIMFeatureCSRROMMap |
- // kFWIMFeatureIRM |
- // kFWIMFeaturePhysicalDMA |
- // kFWIMSetFWIMState | // Knows how to go to sleep
- // kFWIMFeatureAsynchFilters;
- //pFWIMInitializeParams->fwimCSRROMMapLength = 1024;
-
- // Set more features. These are card/MLB dependent, not chip dependent.
- // These values come from macro definitions at the top of this file.
- pFWIMInitializeParams->fwimDeciWatts = HardwareDeciWatts;
- pFWIMInitializeParams->fwimDeciVoltsMinimum = HardwareMinDeciVolts;
- pFWIMInitializeParams->fwimDeciVoltsMaximum = HardwareMaxDeciVolts;
-
- // Allocate Lynx FWIM data.
- // Parts of this struct will be phyiscally addressed, so we need
- // to make sure those parts don't straddle a page boundary. To
- // guarantee this, we put them first in the struct, and we'll
- // page-align the whole struct, and map the first page.
-
- pageSize = GetLogicalPageSize ();
-
- p = PoolAllocateResident (sizeof (LynxFWIMData) + pageSize, true);
- if (p)
- {
- p1 = (Ptr) (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1)); // page-align
- pLynxFWIMData = (LynxFWIMDataPtr) p1;
-
- pLynxFWIMData->baseFWIMDataPtr = p; // Remember the original address returned by PoolAllocateResident
- // so we can de-allocate it later
- pLynxFWIMData->pageSize = pageSize;
- pLynxFWIMData->pageShift = 0;
- while (pageSize >>= 1)
- pLynxFWIMData->pageShift++;
- pageSize = pLynxFWIMData->pageSize;
-
- ioPrep = &pLynxFWIMData->fwimDataIOPrep;
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = 1; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = &pLynxFWIMData->fwimDataPhys; // return phys addr
- ioPrep->rangeInfo.range.base = (void *) pLynxFWIMData; // first addr to map
- ioPrep->rangeInfo.range.length = pageSize; // map one page
-
- // there is no CheckpointIO which matches this. It will be held down forever.
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "FWIMData PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pLynxFWIMData->fwimDataPhys,
- (long) ioPrep->rangeInfo.range.length);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- if (status == noErr)
- {
- pFWIMInitializeParams->fwimSpecificData = (UInt32) pLynxFWIMData;
- }
-
- }
- else
- {
- status = memFullErr;
- }
-
- // for FullReset, below
- HACKdata = pLynxFWIMData;
-
- // Get notification proc and name registry ID.
- if (status == noErr)
- {
- pLynxFWIMData->fwimID = pFWIMInitializeParams->fwimID;
- pLynxFWIMData->FWIMRegEntryID = pFWIMInitializeParams->fwimRegEntryID;
- pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
- }
-
- // Get register base address.
- if (status == noErr)
- {
- status = LynxFWIMGetRegisterBaseAddress (pLynxFWIMData);
- }
-
-
- // Note - sometimes these buffers are used to assemble response packets
- // So even if only a few quads are used in receiving, the rest of the buffer
- // may still be written to later (see LynxFWIMProcessReadBlockPacket, etc.)
-
- // Allocate async / self-ID buffers:
- // Buffers will not span page boundaries (for now, max rcv packet fits in a page)
- // and will be 32-byte aligned for best Lynx performance. To save memory, alloc
- // one big buffer, prep it for I/O, and carve it up. If marked for input, we can
- // re-use it over and over with no VM upkeep.
- // PCLs are PCL-size-aligned, PCL-size is 128 and must divide the page size (easy).
-
- // Use a single allocation for async xmit/rcv buffers and xmit/rcv PCLs. Marking
- // all the memory as "input | output" may prevent some optimizations - future feature.
-
- // Note, because we don't span page boundaries, we don't need to request contig
- // memory. Change to ordinary allocate once it's working. (Asynch Rx descriptors do span
- // pages, fix that first)
-
- if (status == noErr)
- {
- bufPages = ((kAsyncBufs * kPacketBufferSize) / pageSize) + 1; // If packet size divides evenly remove the +1...
- pclsPerPage = pageSize / sizeof (LynxPCL);
- pclPages = (kAsyncBufs + pclsPerPage - 1) / pclsPerPage;
-
- totalAlloc = bufPages; // Space for async rcv bufs
- totalAlloc += 1; // Space for async xmit buf
- totalAlloc += pclPages; // Space for async rcv PCLs
- totalAlloc += 1; // Space for async xmit PCLs
- totalAlloc += 1; // Space for register access PCLs
- totalAlloc += 1; // Round up to page boundary
-
- // Use PoolAllocate to get a page table - don't use the stack.
-
- p = MemAllocatePhysicallyContiguous (totalAlloc * pageSize, true);
-
- if (!p)
- {
- status = memFullErr;
- sprintf (debugStr, "Async buf/PCL alloc failure, asked for %ld",
- (long) totalAlloc * pageSize);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- if (status == noErr)
- {
- // I think MemAllocatePhysicallyContiguous gives us memory starting
- // on a page boundary. But just in case, align ourselves:
-
- pLynxFWIMData->basePCLData = p;
-
- p = (Ptr) ((((UInt32) p) + (pageSize - 1)) & ~(pageSize - 1)); // page-align
-
- // Mark this memory for Input, and learn the physical address
- ioPrep = &pLynxFWIMData->ioPrep;
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = totalAlloc; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = pLynxFWIMData->physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.range.base = (void *) p;
- ioPrep->rangeInfo.range.length = totalAlloc * pageSize;
-
- // There is no CheckpointIO which matches this. The buffers are ours for keeps.
- // !!! If we ever Finalize this FWIM then we need to checkpoint this guy!
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pLynxFWIMData->physAddrs[0],
- (long) ioPrep->rangeInfo.range.length);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- }
-
- // Carve up what we got and store away the addrs
- if (status == noErr)
- {
- // Async rcv buffers (kAsyncBufs)
-
- logPage = p;
- physPage = (Ptr) pLynxFWIMData->physAddrs[0];
-
- for (doBuf = 0; doBuf < kAsyncBufs; doBuf++)
- {
- offset = doBuf * kPacketBufferSize;
- pLynxFWIMData->asyncBuf[doBuf] = logPage + offset;
- pLynxFWIMData->asyncBufPhys[doBuf] = physPage + offset;
- }
-
- // Async xmit buffer (1)
-
- p += (bufPages * pageSize);
- pLynxFWIMData->asyncXmitBuf = p;
- pLynxFWIMData->asyncXmitBufPhys = pLynxFWIMData->physAddrs[bufPages];
-
- // Async rcv PCLs (kAsykcBufs)
- // WARNING rcv code assumes all PCLs are contiguous.
- // If made non-contig, will have to change several places
-
- p += pageSize;
- pLynxFWIMData->asyncPCL = (LynxPCL *) p;
- pLynxFWIMData->asyncPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1];
-
- // Async xmit PCLs (3)
-
- p += (pclPages * pageSize);
- pLynxFWIMData->asyncXmitPCL = (LynxPCL *) p;
- pLynxFWIMData->asyncXmitPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1 + pclPages];
-
- // Register Access PCLs (6) 3 Dummy and 3 Real. 1 set each for task, SIH and interrupt level
- p += pageSize;
- pLynxFWIMData->phyRegAccessLog = (LynxPCL *) p;
- pLynxFWIMData->phyRegAccessPhys = pLynxFWIMData->physAddrs[bufPages + 2 + pclPages];
- }
- }
-
- // Allocate async receive PCL data records.
- if (status == noErr)
- {
- p = PoolAllocateResident (sizeof (LynxAsyncRxPCLData) * kAsyncBufs, true);
-
- if (p) {
- pLynxFWIMData->lynxAsyncRxPCLDataList = (LynxAsyncRxPCLDataPtr) p;
- pLynxFWIMData->baseRxData = p;
- }
- else
- status = memFullErr;
- }
-
- // Allocate async transmit PCL data records.
- if (status == noErr)
- {
- p = PoolAllocateResident (sizeof (LynxAsyncTxPCLData) * kNumAsyncTxPCLs, true);
-
- if (p) {
- pLynxFWIMData->lynxAsyncTxPCLDataList = (LynxAsyncTxPCLDataPtr) p;
- pLynxFWIMData->baseTxData = p;
- }
- else
- status = memFullErr;
- }
-
- // Set up async transmit PCLs.
- if (status == noErr)
- {
- LynxFWIMCreateAsyncTxDummyPCL (pLynxFWIMData);
- LynxFWIMCreateAsyncTxDonePCLSegment (pLynxFWIMData);
- LynxFWIMCreateAsyncTxDataPCL (pLynxFWIMData);
- }
-
- // Create deferred task for handling bus resets.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pLynxFWIMData->busResetDeferredTaskID),
- LynxFWIMResetDeferredTask,
- pLynxFWIMData);
- }
-
- // Assign each channel its default information
- for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ ) {
- pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kChannelUnused;
- pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = false;
- // Create deferred task for each DMA channel. The LynxFWIMDeferredTaskMultiplexer figures out
- // which actual routine to run based on the type of DMA being performed on the channel.
- status = FWCreateDeferredTask (&(pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDT),
- LynxFWIMDeferredTaskMultiplexer,
- pLynxFWIMData);
- if( status )
- break;
-
- }
-
- // Specific channel allocations:
-
- pLynxFWIMData->asyncRxDMA = kAsyncReceiveDMA;
- pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncRxDMA].channelType = kAsyncRcv;
- pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncRxDMA].inUse = true;
-
- pLynxFWIMData->asyncTxDMA = kAsyncTransmitDMA;
- pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncTxDMA].channelType = kAsyncXmit;
- pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncTxDMA].inUse = true;
-
- // Create deferred task for handling miscellaneous interrupts.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pLynxFWIMData->miscInterruptDeferredTaskID),
- LynxFWIMMiscInterruptDeferredTask,
- pLynxFWIMData);
- }
-
- // Install interrupt handler.
- if (status == noErr)
- {
- status = LynxFWIMInstallInterruptHandler (pLynxFWIMData);
- }
-
- // Use config space to enable bus mastering and memory space.
- if (status == noErr)
- {
- status = ExpMgrConfigWriteWord (
- pFWIMRegEntryID, (LogicalAddress) cwCommand,
- (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
- }
-
- if (status == noErr)
- {
- LynxFWIMFullReset();
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxAllocateDMAChannel
- //
- // Allocates a DMA channel.
- //
- static SInt32 LynxAllocateDMAChannel(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- SInt32 dmaChannelNum;
-
- // look for a free channel
- dmaChannelNum = kNumDMAChannels - 1;
- while( dmaChannelNum >= 0 ) {
- if( !pLynxFWIMData->DMAInfo[dmaChannelNum].inUse ) {
-
- pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = true;
- break;
- }
- dmaChannelNum--;
- }
-
- return(dmaChannelNum);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxDeAllocateDMAChannel
- //
- // Deallocates a DMA channel
- //
- static void LynxDeAllocateDMAChannel(
- LynxFWIMDataPtr pLynxFWIMData,
- SInt32 dmaChannelNum)
- {
-
- pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = false;
- pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kChannelUnused;
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMFinalize
- //
- // This is the FWIM finalizing proc. It deallocates everything.
- // Presumes we only get called if we successfully initialized.
- //
-
- static OSStatus LynxFWIMFinalize(
- FWIMFinalizeParamsPtr pFWIMFinalizeParams)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- SInt32 dmaChannelNum;
- UInt32 lynxReg;
- UInt32 phyReg;
- UInt32 delay;
- AbsoluteTime timeRemaining;
-
- // Get our internal data.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMFinalizeParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Clear Contender
- if( pLynxFWIMData->extendedPhyRegs ) {
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
- phyReg &= ~kLynxExtPhyCntd;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
- }
- else {
- // Program the contender bit to be clear on next reset.
- //zzz ought to have routine for setting gpios.
- lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
- lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
- pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
- SynchronizeIO ();
- pLynxRegs->gpioData[1] = EndianSwapImm32Bit (0);
- SynchronizeIO ();
- }
-
-
- LynxFWIMDisableComparators(pLynxFWIMData);
-
- // Kill off interrupts since we won't be able to respond anymore.
- pLynxRegs->pciInterruptEnable = 0;
-
- // Issue a reset so everybody else knows our Link just went dark.
- // IBR reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
- phyReg |= kLynxPhyIBR;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
-
- // Wait for root holdoff bit to go away. If it doesn't go away in say 100ms give up and just turn it off.
-
- for( delay = 0; delay < 10; delay++ ) {
-
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
- if( phyReg & kLynxPhyRHB )
- break;
-
- DelayForHardware(DurationToAbsolute(durationMillisecond * 10));
-
- }
-
- if( delay >= 10 ) {
- // Clear the root holdoff bit in the PHY. RHB reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
- phyReg &= ~kLynxPhyRHB;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
- }
-
- // Cancel any outstanding timers.
-
- if( pLynxFWIMData->holdoffResetRequestsTimerSet )
- CancelTimer (pLynxFWIMData->holdoffResetRequestsTimerID, &timeRemaining);
-
- if( pLynxFWIMData->requestTimeoutTimerSet )
- CancelTimer (pLynxFWIMData->requestTimeoutTimerID, &timeRemaining);
-
- if( pLynxFWIMData->delayedResetTimerSet )
- CancelTimer (pLynxFWIMData->delayedResetTimerID, &timeRemaining);
-
- if( pLynxFWIMData->phyRegTimerID )
- CancelTimer (pLynxFWIMData->phyRegTimerID, &timeRemaining);
-
- if( pLynxFWIMData->phyPowerTimerID )
- CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);
-
- // Get rid of our deferred tasks
- for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ )
- FWDisposeDeferredTask( pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDT );
- FWDisposeDeferredTask( pLynxFWIMData->miscInterruptDeferredTaskID );
- FWDisposeDeferredTask( pLynxFWIMData->busResetDeferredTaskID );
-
- // Checkpoint the PMFIO's we did when initializing the SIM.
- CheckpointIO (pLynxFWIMData->fwimDataIOPrep.preparationID, kNilOptions);
- CheckpointIO (pLynxFWIMData->ioPrep.preparationID, kNilOptions);
-
- // Put the interrupt functions back the way we found them.
- InstallInterruptFunctions
- (pLynxFWIMData->interruptSetMember.setID,
- pLynxFWIMData->interruptSetMember.member,
- pLynxFWIMData->oldInterruptRefCon,
- pLynxFWIMData->oldInterruptHandler,
- pLynxFWIMData->interruptOldEnabler,
- pLynxFWIMData->interruptOldDisabler);
-
- // Make interrupt mananger think everything is turned off
- (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
- pLynxFWIMData->oldInterruptRefCon);
-
- // Turn off access to the card's memory space
- ExpMgrConfigWriteWord (&(pLynxFWIMData->FWIMRegEntryID), (LogicalAddress) cwCommand,0);
-
- // Give back any memory we might have allocated.
- PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseRxData);
- PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseTxData);
- MemDeallocatePhysicallyContiguous ((LogicalAddress) pLynxFWIMData->basePCLData);
- PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseFWIMDataPtr); // Needs to be last (obviously...)
-
- return (noErr);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPollInterrupts
- //
- // This proc checks for pending interrupts.
- //
- // 2/10/98 I changed this function a lot but don't worry - it never gets called
- // unless you build with forVMBackingStore turned on. There is no provision whatsoever
- // in the existing FSL for polling interrupts. -DCB
- //
-
- static OSStatus LynxFWIMPollInterrupts(
- FWIMPollInterruptsParamsPtr pFWIMPollInterruptsParams)
- {
- OSStatus status = noErr;
- LynxFWIMDataPtr pLynxFWIMData;
- UInt32 dmaChannelNum;
-
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMPollInterruptsParams->fwimSpecificData;
-
- if( pLynxFWIMData->phyNotPowered )
- return( accessErr ); // !!! Proper error?
-
- // Disable both VM User Code AND Lynx interrupts while we're in here so that
- // dispatch interrupts can behave as if it was actually at hardware interrupt
- // level.
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
- (*(pLynxFWIMData->interruptDisabler)) (pLynxFWIMData->interruptSetMember,
- (void *) pLynxFWIMData); // >>•••••••>> Ints Off
-
- // Do we care if we handled an interrupt here? It could be bad if we cleared an int while
- // interrupt services was running the tree. OTOH this might not be the place to fix it.
- LynxFWIMDispatchInterrupts(pLynxFWIMData);
-
- (*(pLynxFWIMData->interruptEnabler)) (pLynxFWIMData->interruptSetMember,
- (void *) pLynxFWIMData); // <<•••••••<< Ints On
-
-
- // LynxFWIMDispatchInterrupts may have enqueued some deferred tasks. If we are polling they
- // won't get run normally so we have to do it manually here. We don this with ints off
- // since we might actually be at interrupt level 0 (but in the middle of processing SIHs).
-
- for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ ) {
- if( pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDTScheduled )
- LynxFWIMDeferredTaskMultiplexer( pLynxFWIMData, (void *)dmaChannelNum );
- }
-
- if( pLynxFWIMData->busResetDTScheduled )
- LynxFWIMResetDeferredTask(pLynxFWIMData,nil);
-
- if( pLynxFWIMData->miscInterruptDTScheduled )
- LynxFWIMMiscInterruptDeferredTask(pLynxFWIMData,nil);
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMGetRegisterBaseAddress
- //
- // This proc uses the name registry to find the base address of the registers.
- //
-
- static OSStatus LynxFWIMGetRegisterBaseAddress(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- RegEntryIDPtr pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
- PCIAssignedAddressPtr tempFWIMAddressesStorage = nil,
- pFWIMAddresses;
- Ptr pFWIMAddressesEnd;
- DeviceLogicalAddressPtr tempFWIMLogicalAddressesStorage = nil,
- pFWIMLogicalAddresses;
- RegPropertyValueSize propSize;
- UInt32 assignedAddressesSize;
- Boolean done;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMGetRegisterBaseAddress");
-
- // Get assigned addresses property.
- status = RegistryPropertyGetSize
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kPCIAssignedAddressProperty,
- &propSize);
-
- if (status == noErr)
- {
- tempFWIMAddressesStorage =
- (PCIAssignedAddressPtr) PoolAllocateResident (propSize, false);
- if (tempFWIMAddressesStorage == nil)
- status = memFullErr;
- else
- pFWIMAddresses = tempFWIMAddressesStorage;
- }
-
- if (status == noErr)
- {
- status = RegistryPropertyGet
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kPCIAssignedAddressProperty,
- pFWIMAddresses,
- &propSize);
- assignedAddressesSize = propSize;
- }
-
- // Get logical addresses property.
- if (status == noErr)
- {
- status = RegistryPropertyGetSize
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
- &propSize);
- }
-
- if (status == noErr)
- {
- tempFWIMLogicalAddressesStorage =
- (DeviceLogicalAddressPtr) PoolAllocateResident (propSize, false);
- if (tempFWIMLogicalAddressesStorage == nil)
- status = memFullErr;
- else
- pFWIMLogicalAddresses = tempFWIMLogicalAddressesStorage;
- }
-
- if (status == noErr)
- {
- status = RegistryPropertyGet
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
- pFWIMLogicalAddresses,
- &propSize);
- }
-
- // Scan addresses until we find the one at config space 0x10.
- if (status == noErr)
- {
- pFWIMAddressesEnd = ((Ptr) pFWIMAddresses) + assignedAddressesSize;
- done = false;
-
- while ((((Ptr) pFWIMAddresses) < pFWIMAddressesEnd) && (!done))
- {
- if (pFWIMAddresses->registerNumber == 0x10)
- {
- // There is a certain prototype system in which Open Firmware
- // doesn't seem to work quite right yet. If we find that the
- // base register is zero, substitute another value for now.
-
- if (!*pFWIMLogicalAddresses)
- {
- pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) pFWIMAddresses->address.lo;
-
- sprintf (debugStr, "Base register 0, using %08lx", (long) pFWIMAddresses->address.lo);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- else
- {
- pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) *pFWIMLogicalAddresses;
- }
- done = true;
- }
-
- pFWIMAddresses++;
- pFWIMLogicalAddresses++;
- }
-
- if (!done)
- status = paramErr;
- }
-
- // Deallocate temp storage.
- if (tempFWIMAddressesStorage != nil)
- PoolDeallocate ((LogicalAddress) tempFWIMAddressesStorage);
-
- if (tempFWIMLogicalAddressesStorage != nil)
- PoolDeallocate ((LogicalAddress) tempFWIMLogicalAddressesStorage);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInstallInterruptHandler
- //
- // This proc installs the chip interrupt handler.
- //
-
- static OSStatus LynxFWIMInstallInterruptHandler(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- RegEntryIDPtr pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
- ISTProperty interruptSets;
- InterruptSetID interruptSetID;
- InterruptMemberNumber interruptMemberNumber;
- void *oldInterruptRefCon;
- InterruptHandler oldInterruptHandler;
- InterruptEnabler interruptEnabler;
- InterruptDisabler interruptDisabler;
- RegPropertyValueSize propSize;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMInstallInterruptHandler");
-
- // Get our interrupt set from the name registry.
- propSize = sizeof (ISTProperty);
- status = RegistryPropertyGet (pFWIMRegEntryID, kISTPropertyName,
- &interruptSets, &propSize);
- interruptSetID = interruptSets[kISTChipInterruptSource].setID;
- interruptMemberNumber = interruptSets[kISTChipInterruptSource].member;
-
- // Get the interrupt enabler and disabler for our chip interrupt set.
- if (status == noErr)
- {
- status = GetInterruptFunctions
- (interruptSetID, interruptMemberNumber,
- &oldInterruptRefCon, &oldInterruptHandler,
- &interruptEnabler, &interruptDisabler);
- }
-
- // Install the refCon and interrupt handler for our chip interrupt set.
- if (status == noErr)
- {
- status = InstallInterruptFunctions
- (interruptSetID, interruptMemberNumber,
- pLynxFWIMData, (InterruptHandler) LynxFWIMInterruptHandler,
- LynxFWIMInterruptEnabler, LynxFWIMInterruptDisabler);
- }
-
- // Add info to our FWIM Data record.
- if (status == noErr)
- {
- pLynxFWIMData->interruptSetMember.setID = interruptSetID;
- pLynxFWIMData->interruptSetMember.member = interruptMemberNumber;
- pLynxFWIMData->oldInterruptRefCon = oldInterruptRefCon;
- pLynxFWIMData->oldInterruptHandler = oldInterruptHandler;
- pLynxFWIMData->interruptEnabler = LynxFWIMInterruptEnabler;
- pLynxFWIMData->interruptOldEnabler = interruptEnabler;
- pLynxFWIMData->interruptDisabler = LynxFWIMInterruptDisabler;
- pLynxFWIMData->interruptOldDisabler = interruptDisabler;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMcrc16
- //
- // Compute the CRC-16 value of a block of quadlets.
- // Adapted from Table 23 of IEEE 1212.
- // Takes quadlet pointer and count of quadlets
-
- static UInt16 LynxFWIMcrc16(
- UInt32 *data,
- UInt32 count)
- {
- SInt32 shift;
- UInt16 sum, next = 0;
- UInt32 doCount = count, *doData = data;
-
- while (doCount--)
- {
- for (shift = 28; shift >= 0; shift -= 4) // 8 times, 4 bits each time
- {
- sum = ((next >> 12) ^ (*doData >> shift)) & 0x0f; // get 4 bits
- next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; // apply them
- }
- doData++;
- }
-
- return next;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMControlEEPROM
- //
- // Modify (up to) three EEPROM control bits: Clock, Data, and Timer.
- // There isn't currently any place we're called without the timer option.
-
- static void LynxFWIMControlEEPROM(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 clock,
- UInt32 data,
- UInt32 timer)
- {
- UInt32 eepromTemp;
-
- eepromTemp = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
- SynchronizeIO ();
-
- if (clock == kClockHi)
- eepromTemp |= EndianSwapImm32Bit (kLynxEEPCLK);
- else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPCLK);
-
- if (data != kNoData)
- {
- if (data == kDataHi)
- eepromTemp |= EndianSwapImm32Bit (kLynxEEPDAT);
- else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPDAT);
- }
-
- if (timer == kStartTimer)
- eepromTemp &= ~EndianSwapImm32Bit (kLynxTIMER_5USEC);
- else eepromTemp |= EndianSwapImm32Bit (kLynxTIMER_5USEC);
-
- pLynxFWIMData->pLynxRegisters->serialEEPROMControl = eepromTemp;
- SynchronizeIO ();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWaitForEEPROM
- //
- // Wait for a previously set timer to expire, then return the EEPROM data bit
-
- static UInt32 LynxFWIMWaitForEEPROM(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- UInt32 e = 0;
-
- while (!(e & EndianSwapImm32Bit (kLynxTIMER_5USEC)))
- {
- e = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
- SynchronizeIO ();
- }
-
- return ((e & EndianSwapImm32Bit (kLynxEEPDAT)) != 0);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSendEEPROMBit
- //
- // Send one bit to the serial EEPROM. To do this, assert the data bit, wait for it
- // to be stable, then raise the clock signal for 5us to send the bit, then lower the
- // clock signal.
- // If we do these back to back we might be able to remove the final clock wait.
-
- static void LynxFWIMSendEEPROMBit(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 bit)
- {
- int dataBit = bit ? kDataHi : kDataLo;
-
- // Set initial state
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // Raise clock to send data
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, dataBit, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // Drop clock to end this bit
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSendEEPROMByte
- //
- // Send one byte to the EEPROM, MSB first
-
- static void LynxFWIMSendEEPROMByte(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 sendByte)
- {
- int i;
- UInt8 sendMe = sendByte;
-
- for (i = 0; i < 8; i++)
- {
- LynxFWIMSendEEPROMBit (pLynxFWIMData, sendMe >> 7); // Send current MSB
- sendMe = sendMe << 1; // Rotate next bit into MSB
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReadEEPROMBit
- //
-
- static UInt32 LynxFWIMReadEEPROMBit(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- UInt32 data;
-
- // When reading the data, we have to take the Data line Hi (tristate)
- // and then see which way the ROM pulls it (high or low)
-
- // Set initial state
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // Now take clock high to receive data
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kNoData, kStartTimer);
- data = LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // set clock low to end this bit
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kNoData, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- return data;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReadEEPROMByte
- //
- // Read one byte from the EEPROM, MSB first
-
- static UInt8 LynxFWIMReadEEPROMByte(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- int i;
- UInt8 readByte = 0;
-
- for (i = 0; i < 8; i++)
- readByte = (readByte << 1) | LynxFWIMReadEEPROMBit (pLynxFWIMData);
-
- return readByte;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartEEPROM
- //
- // Send a special "Start" signal to the EEPROM, by taking the data line
- // low while holding the clock line high.
-
- static void LynxFWIMStartEEPROM (
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // While clock is still high, take data low - this signals a "start"
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // Now take clock low to signal end of "start"
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStopEEPROM
- //
- // Send a special "Stop" signal to the EEPROM, by taking the data line
- // low while holding the clock line high.
-
- static void LynxFWIMStopEEPROM (
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // While clock is still high, take data high - this signals a "stop"
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // Now take clock low to signal end of "stop"
- LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessEEPROM
- //
- // Read data out of the Lynx serial EEPROM, to determine our Unique ID, and
- // some configuration info like how much SRAM we have on board. This is lots
- // of fun because we have to manually clock the EEPROM by wiggling the clock
- // and data lines around under software control.
- //
- // This takes roughly 30 milliseconds, if the Lynx 5 microsecond timer is accurate
-
- // still to do:
- // checksum
-
- static void LynxFWIMProcessEEPROM(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- OSStatus status = noErr;
- UInt32 eepromState, readQuad, scanQuad, scanKey;
- SInt32 scanLen, scanPos, modulePos;
- LynxEEPROMBasePtr eepromBase;
- LynxEEPROMInfoPtr eepromInfo;
-
- eepromBase = (LynxEEPROMBasePtr) pLynxFWIMData->eepromData;
- eepromInfo = &(pLynxFWIMData->eepromInfo);
-
- // Prepare invalid/default values in case something goes wrong
-
- pLynxFWIMData->eepromValid = false;
- modulePos = 0; // Illegal value
- eepromInfo->module_Vendor_Id = 0xffffffff; // Legal values are only 24 bits
- eepromInfo->module_Hardware_Version = 0xffffffff; // same
- eepromInfo->node_Hardware_Version = 0xffffffff; // same
- eepromInfo->sram_Quads = 0; // Assume 0 if key not found
- eepromInfo->auxRam_Quads = 0; // same
- eepromInfo->aux_Device = 0; // same
-
- // We can skip all this if the EEPROM is missing or broken:
-
- eepromState = EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->serialEEPROMControl);
- if (eepromState & (kLynxEEPERR | kLynxEEPCHKERR | kLynxNOTPRS))
- return;
-
- // Reset the EEPROM control register & state
-
- pLynxFWIMData->pLynxRegisters->serialEEPROMControl =
- EndianSwapImm32Bit (kLynxEEPENA | kLynxEEPDAT | kLynxTIMER_5USEC);
- SynchronizeIO ();
- LynxFWIMWaitForEEPROM (pLynxFWIMData);
-
- // First we send a special "start" signal to get the EEPROM's attention.
-
- LynxFWIMStartEEPROM (pLynxFWIMData);
-
- // In order to do a random read, we pretend to initiate a write. That
- // sets the address at which the EEPROM will either read or write.
-
- // The WRITE message is formed like this: 10100000 == 0xa0
- // Identifies NM24Cxx serial EEPROM ----> 1010 0 <--- 0 indicates WRITE
- // Indicates device/block (page) address ---> 000
-
- LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa0); // WRITE command 01010000
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // strobe for Ack
-
- LynxFWIMSendEEPROMByte (pLynxFWIMData, 0x00); // Data address 00000000
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // strobe for Ack
-
- // Now we're done with the dummy write. Send another "start" condition.
-
- LynxFWIMStartEEPROM (pLynxFWIMData);
-
- // READ command is same as WRITE command above, except for last bit.
-
- LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa1); // READ command 01010001
-
- // Read the minimum-sized EEPROM (256 bytes) into memory.
-
- for (scanPos = 0; scanPos < kLynxMinEEPROMQuads; scanPos++)
- {
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // ack previous Send/Read
-
- readQuad = LynxFWIMReadEEPROMByte (pLynxFWIMData);
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // ack
-
- readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // ack
-
- readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
- LynxFWIMSendEEPROMBit (pLynxFWIMData, 0); // ack
-
- readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
-
- pLynxFWIMData->eepromData[scanPos] = readQuad;
- }
-
- // Now we are supposed to send a STOP condition.
-
- LynxFWIMStopEEPROM (pLynxFWIMData);
-
- // We're done with the EEPROM. Extract some info from what we got.
-
- if (eepromBase->crcLen > kLynxMinEEPROMQuads) // Protect against bogus lengths
- return;
-
- if (eepromBase->crc !=
- LynxFWIMcrc16 ((UInt32 *) eepromBase->busInfoBlock, (UInt32) eepromBase->crcLen))
- return;
-
- // If we passed CRC on the Bus Info block, declare the EEPROM to be valid.
- // This means that at least the unique ID is present and passes CRC, which
- // is all we currently use anyway.
-
- pLynxFWIMData->eepromValid = true;
- BlockCopy ((Ptr) &(eepromBase->busInfoBlock), (Ptr) &(eepromInfo->busInfoBlock), 16);
-
- scanLen = eepromBase->romData[0] >> 16; // Root directory length in quadlets
-
- if (scanLen > kLynxMinEEPROMQuads) // Protect against bogus lengths
- return;
-
- if ((eepromBase->romData[0] & 0xffff) !=
- LynxFWIMcrc16 (&(eepromBase->romData[1]), scanLen))
- return;
-
- // Scan the root directory
- for (scanPos = 1; scanPos <= scanLen; scanPos++)
- {
- scanQuad = eepromBase->romData[scanPos];
- scanKey = scanQuad >> 24;
-
- switch (scanKey)
- {
- case kLynxEEPROMKeyModuleVendorID:
- eepromInfo->module_Vendor_Id = scanQuad & 0xffffff;
- break;
-
- case kLynxEEPROMKeyModuleHardwareVersion:
- eepromInfo->module_Hardware_Version = scanQuad & 0xffffff;
- break;
-
- case kLynxEEPROMKeyNodeHardwareVersion:
- eepromInfo->node_Hardware_Version = scanQuad & 0xffffff;
- break;
-
- case kLynxEEPROMKeyModuleDependentInfo:
- modulePos = scanPos + (scanQuad & 0xffffff);
- break;
-
- default: break;
- }
- }
-
- // Scan the module-dependent directory, if found
- if (modulePos)
- {
- scanLen = eepromBase->romData[modulePos] >> 16; // Module dep dir length in quadlets
-
- if (scanLen > kLynxMinEEPROMQuads) // Protect against bogus lengths
- return;
-
- if ((eepromBase->romData[modulePos] & 0xffff) !=
- LynxFWIMcrc16 (&(eepromBase->romData[modulePos + 1]), scanLen))
- return;
-
- for (scanPos = 1; scanPos <= scanLen; scanPos++)
- {
- scanQuad = eepromBase->romData[modulePos + scanPos];
- scanKey = scanQuad >> 24;
-
- switch (scanKey)
- {
- case kLynxEEPROMKeySramQuads:
- eepromInfo->sram_Quads = scanQuad & 0xffffff;
- break;
-
- case kLynxEEPROMKeyAuxRamQuads:
- eepromInfo->auxRam_Quads = scanQuad & 0xffffff;
- break;
-
- case kLynxEEPROMKeyAuxDevice:
- eepromInfo->aux_Device = scanQuad & 0xffffff;
- break;
-
- default:
- break;
- }
- }
- }
-
- #if 0
- sprintf (debugStr, "EEPROM Node Vendor ID %06lx Chip ID %02lx%08lx",
- (long) eepromInfo->busInfoBlock[2] >> 8,
- (long) eepromInfo->busInfoBlock[2] & 0xff,
- (long) eepromInfo->busInfoBlock[3]);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- sprintf (debugStr, "EEPROM Mod Vendor ID %06lx Mod HW Vers %06lx Node HW Vers %06lx",
- (long) eepromInfo->module_Vendor_Id,
- (long) eepromInfo->module_Hardware_Version,
- (long) eepromInfo->node_Hardware_Version);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- sprintf (debugStr, "EEPROM SRAM size %06lx (q) AUX RAM size %06lx (q) AUX Device %06lx",
- (long) eepromInfo->sram_Quads,
- (long) eepromInfo->auxRam_Quads,
- (long) eepromInfo->aux_Device);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- #endif
-
- return;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMFullReset
- //
- // This function flips the SWRST bit to fully reset the Lynx card,
- // Then re-establishes interrupts, DMA, etc.
- // This is used both during FWIM Install and any time the card jams up.
- // As far as I know this does not cause a bus reset.
- //
-
- static void LynxFWIMFullReset(void)
- {
- LynxFWIMDataPtr pLynxFWIMData = HACKdata;
- LynxRegistersPtr pLynxRegs;
- UInt32 nodeAddress;
- OSStatus status = noErr;
- static UInt32 firstTime = 1;
- UInt32 physicalID;
- UInt32 oldNodeID;
- UInt8 phyExtended;
- UInt8 phyPorts;
-
- // FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMFullReset");
-
- // Do we need to cancel any timers?!?
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &oldNodeID ))
- return;
-
- oldNodeID = EndianSwap32Bit (oldNodeID);
-
- // Reset everything:
- pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxSWRST);
- SynchronizeIO ();
- if (pLynxRegs->miscControl & EndianSwapImm32Bit (kLynxSWRST))
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Should have waited for SWRST");
-
- // Lynx errata for pre-REV A advises this:
- // Lynx errata for REV A advises NOT to do this:
- //pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxENA_POST_WR | kLynxENA_SLV_BURST);
- SynchronizeIO ();
-
- if (firstTime)
- LynxFWIMProcessEEPROM (pLynxFWIMData);
-
- // Set up the FIFOs.
- LynxFWIMSetupFIFOs (pLynxFWIMData);
-
- // Set up DMA for packet reception (Turns on comparators)
-
- pLynxFWIMData->pNextAsyncPCL = nil; // Make sure we start processing PCLs from the beginning.
-
- LynxFWIMPrepareAsyncDMA (pLynxFWIMData, pLynxFWIMData->asyncRxDMA);
-
- // Some information about the DMA comparators
- // (The Lynx 0.10 spec is very confusing)
-
- // This makes all self-ID, async, and isoch arrive on one DMA channel (0)
- // including async packets not directed to our node/bus ID:
- // Set all enables and values to 0, except for 0x0B0C: RCV_SELF_ID_EN | EN_CH_COMPARE
-
- // For the same as above on channel 0, except with all isoch going to channel
- // 1 instead, set 0x0B04 to 0x000000A0 ('Async tcode encoding ("normal") -> GRF')
- // Also turn on EN_CH_COMPARE for channel 1
-
- // Same as previous, but send async that isn't for our own node onto channel 1
- // along with all the isochronous packets:
- // set 0x0B0C to RCV_SELF_ID_EN | EN_CH_COMPARE | DEST_ID_SEL (00001)
-
- // Here's what we actually do - all of the above, plus, restrict channel 1 to
- // isoch only, so we no longer receive async packets that aren't for our node.
- // Set 0x0B14 to 0x00000090 ('Iso tcode encoding ("normal") -> GRF')
-
- // This controls retries ONLY for busy acknowledge, not data errors or no-ack
- // cases. Busy ack means the other node really is there, but just can't handle
- // our packet right now (possibly because they experienced a FIFO overflow).
- // It's probably good to try a bunch of times, because busy is a rare case, and
- // we always expect to get through eventually.
-
- // Mark up to 32 retries, 16 cycles apart (1/15 second max delay)
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->retryCountInterval,
- (UInt32) EndianSwapImm32Bit (0x00001020) ))
- return;
-
- // Enable Receiver and Transmitter
- LynxFWIMSetLinkControl ( pLynxFWIMData,
- EndianSwapImm32Bit(
- kLynxTX_ISO_EN |
- kLynxRX_ISO_EN |
- kLynxTX_ASYNC_EN |
- kLynxRX_ASYNC_EN |
- kLynxRCV_COMP_VALID));
-
- if (firstTime)
- {
- // Find out what kind of PHY we have. This is done by looking at the Extended field
- // in the new PHY register set definition. If it is all 1's (0x07) then we have the
- // extended register file. If anything is zero we don't.
- // Note that this field overlaps partially with the SPD field in the old PHY register
- // file but that's OK since it also overlaps with the REV field which will always
- // be zero.
-
- phyExtended = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxExtPhyExtAddress);
- phyExtended = (phyExtended & kLynxExtPhyExt) >> kLynxExtPhyExtPhase;
-
- if( phyExtended == 0x07 ){ // Will never be true with the old PHY,
- pLynxFWIMData->extendedPhyRegs = true;
- pLynxFWIMData->receiveLocalSelfID = true;
-
- // Find out how many ports we have
- phyPorts = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxExtPhyNPAddress);
- phyPorts = (phyPorts & kLynxExtPhyNP) >> kLynxExtPhyNPPhase;
- }
- else {
- pLynxFWIMData->extendedPhyRegs = false;
-
- #ifdef FujiPHY
- #if FujiPHY
- // Some cards have a FujiFilm MD8404 PHY. This PHY does not claim to
- // have extended registers. But it *does* send the local self-ID.
- pLynxFWIMData->receiveLocalSelfID = true;
- #else
- pLynxFWIMData->receiveLocalSelfID = false;
- #endif
- #endif
-
- #ifndef FujiPHY
- pLynxFWIMData->receiveLocalSelfID = false;
- #endif
-
- // Find out how many ports we have
- phyPorts = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxPhyNPAddress);
- phyPorts = (phyPorts & kLynxPhyNP) >> kLynxPhyNPPhase;
- }
-
- pLynxFWIMData->numPHYPorts = phyPorts;
-
- // Get physical ID.
- NoPhyReset = 1;
- physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPhysicalIDAddress);
- NoPhyReset = 0;
- physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
-
- // Set our bus number to default 0x3FF.
- //zzz how will we determine correct bus number.
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &nodeAddress ))
- return;
-
- nodeAddress = EndianSwap32Bit (nodeAddress);
-
- nodeAddress = (nodeAddress & (~kLynxBUS_ID)) |
- ((0x3FF << kLynxBUS_IDPhase) & kLynxBUS_ID);
- nodeAddress = (nodeAddress & (~kLynxNODE_ID)) |
- ((physicalID << kLynxNODE_IDPhase) & kLynxNODE_ID);
-
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32) EndianSwap32Bit (nodeAddress) ))
- return;
- }
- else
- {
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32) EndianSwap32Bit (nodeAddress) ))
- return;
- }
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Enable interrupts");
-
- if (firstTime)
- {
- // Enable chip interrupts.
- if (status == noErr)
- {
- (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
- pLynxFWIMData->oldInterruptRefCon);
-
- }
- }
-
- // Enable interrupts for bus resets, phy registers, and DMA PCL ints
- {
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptEnable,
- (UInt32) EndianSwapImm32Bit (kLynxLINK_INT |
- kLynxPHY_BUSRESET |
- kLynxPHY_REG_RCVD)))
- return;
-
- // Enable additional interrupts only if we are running FireBug.
- // Interrupts will be reported to FireBug.
- // Normally there's nothing we can do about these interrupts.
-
- #ifdef LynxFireBug
- if( LynxFWIMSetRegisterBits( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptEnable,
- (UInt32) EndianSwapImm32Bit (kLynxPHY_TIME_OUT |
- kLynxIT_STUCK |
- kLynxAT_STUCK |
- kLynxTC_ERR |
- kLynxITF_UNDER_FLOW |
- kLynxATF_UNDER_FLOW |
- kLynxIARB_FAILED)))
- return;
-
- // Note: Checking for CYC_LOST is tricky. We'll get 8000/second
- // unless we're cycle master or someone else is. There can be
- // periods with no cycle master, and, sending out the message about
- // the interrupts repeatedly could prevent us from establishing a
- // new cycle master.
-
- // Checking for CYC_ARB_FAILED is also tricky. It seems to indicate
- // that the bus was not idle when the cycle timer rolled over. This
- // means that the cycle start packet was delayed, not lost. That may
- // not be of great interest.
-
- // Header Error interrupt is broken on revA parts
-
- if ((pLynxRegs->configClassRevID >> 24) == 0) {
-
- if( LynxFWIMSetRegisterBits( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptEnable,
- (UInt32) EndianSwapImm32Bit (kLynxHDR_ERR)))
- return;
-
- }
-
- #endif
- // Enable appropriate Interrupts
- LynxFWIMInterruptSetup( pLynxFWIMData );
-
- }
-
- // Enable Cycle Timer.
- {
- LynxFWIMSetLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCTIMEREN));
- }
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Survived!");
-
- firstTime = 0;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDisableComparators
- //
- // Disables the comparators for the various (up to 3) rx channels. Uses the
- // safe register access routines.
- //
- static OSStatus LynxFWIMDisableComparators (
- LynxFWIMDataPtr pLynxFWIMData )
-
- {
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
-
- status = LynxFWIMClearRegisterBits( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
- (UInt32) EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
- SynchronizeIO ();
-
- return( status );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMEnableComparators
- //
- // Enables the comparators for the various (up to 3) rx channels.
- //
- static OSStatus LynxFWIMEnableComparators (
- LynxFWIMDataPtr pLynxFWIMData )
- {
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- status = LynxFWIMSetRegisterBits( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
- (UInt32) EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
- SynchronizeIO ();
-
- return( status );
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInterruptSetup
- //
- // Figures out which interrupts to enable.
- //
-
- void LynxFWIMInterruptSetup(
- LynxFWIMDataPtr pLynxFWIMData)
- {
-
- UInt32 dmaChannel;
- LynxRegistersPtr pLynxRegs;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Enable PCL interrupts for any channel doing async receive or isochronous anything
- pLynxFWIMData->interruptMask = kLynxP1394_INT;
- for( dmaChannel = 0; dmaChannel < kNumDMAChannels; dmaChannel++ ) {
-
- switch( pLynxFWIMData->DMAInfo[dmaChannel].channelType ) {
-
- case kAsyncRcv:
- case kIsochRcv:
- case kIsochXmit:
- switch( dmaChannel ) {
-
- case 0:
- pLynxFWIMData->interruptMask |= kLynxDMA0_PCL;
- break;
- case 1:
- pLynxFWIMData->interruptMask |= kLynxDMA1_PCL;
- break;
- case 2:
- pLynxFWIMData->interruptMask |= kLynxDMA2_PCL;
- break;
- case 3:
- pLynxFWIMData->interruptMask |= kLynxDMA3_PCL;
- break;
- case 4:
- pLynxFWIMData->interruptMask |= kLynxDMA4_PCL;
- break;
-
- }
- break;
-
- default:
- break;
- }
- }
-
- if( !pLynxFWIMData->intsDisabledCount && !pLynxFWIMData->phyNotPowered ) {
- pLynxRegs->pciInterruptEnable =
- EndianSwap32Bit ( pLynxFWIMData->interruptMask );
- SynchronizeIO ();
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMExceptionHandler
- //
- // This proc handles exceptions.
- //
-
- static OSStatus LynxFWIMExceptionHandler(
- ExceptionInformationPowerPC *theException)
- {
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMExceptionHandler");
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInterruptHandler
- //
- // This is the handler proc for chip interrupts.
- //
-
- static InterruptMemberNumber LynxFWIMInterruptHandler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon,
- UInt32 interruptCount)
- {
- OSStatus status;
-
- LynxFWIMDisableVMUserCode((LynxFWIMDataPtr) interruptRefCon);
-
- if( LynxFWIMDispatchInterrupts ((LynxFWIMDataPtr) interruptRefCon) )
- status = kIsrIsComplete;
- else
- status = kIsrIsNotComplete;
-
- LynxFWIMEnableVMUserCode((LynxFWIMDataPtr) interruptRefCon);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInterruptEnabler
- //
- // Enables interrupts. We have our own functions for this because if a card is
- // behind a bridge you can't be guaranteed that the default functions will always
- // do the right thing. Also this one keeps a count of how many times we've disabled
- // interrupts and won't enable them until the count is zero.
- //
-
- static void LynxFWIMInterruptEnabler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon )
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
-
- pLynxFWIMData = (LynxFWIMDataPtr) interruptRefCon;
-
- // Get our register base address.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- DecrementAtomic( &pLynxFWIMData->intsDisabledCount );
-
- if( !pLynxFWIMData->intsDisabledCount ) {
- (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
- pLynxFWIMData->oldInterruptRefCon);
- pLynxRegs->pciInterruptEnable = EndianSwap32Bit ( pLynxFWIMData->interruptMask ); // LynxFWIMInterruptSetup keeps track of which bit to enable
-
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInterruptDisabler
- //
- // Disables interrupts. We have our own functions for this because if a card is
- // behind a bridge you can't be guaranteed that the default functions will always
- // do the right thing. Also this one keeps a count of how many times we've disabled
- // interrupts and won't enable them until the count is zero.
- //
-
- static InterruptSourceState LynxFWIMInterruptDisabler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon )
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- SInt32 previousState;
-
- pLynxFWIMData = (LynxFWIMDataPtr) interruptRefCon;
-
- // Get our register base address.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- previousState = IncrementAtomic( &pLynxFWIMData->intsDisabledCount );
-
- pLynxRegs->pciInterruptEnable = 0; // LynxFWIMInterruptSetup keeps track of which bit to enable
-
- if( !previousState )
- (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
- pLynxFWIMData->oldInterruptRefCon);
-
- if( previousState )
- return( kSourceWasDisabled);
- else
- return( kSourceWasEnabled);
-
- }
-
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDispatchInterrupts
- //
- // This proc dispatches any pending interrupts.
- //
-
- static Boolean LynxFWIMDispatchInterrupts(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxRegistersPtr pLynxRegs;
- UInt32 interruptStatus, interruptStatusLittleEndian;
-
- // Get our register base address.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Read PCI interrupt status register.
- interruptStatusLittleEndian = pLynxRegs->pciInterruptStatus;
- interruptStatus = EndianSwap32Bit (interruptStatusLittleEndian);
-
- // Note - there are lots of kinds of ints other than 1394 and DMA
- // that can happen. We'll probably want to catch some of them.
-
- #if FW_DEBUG_BUILD
-
- pLynxFWIMData->interruptValues[0] = pLynxFWIMData->interruptValues[1];
- pLynxFWIMData->interruptValues[1] = pLynxFWIMData->interruptValues[2];
- pLynxFWIMData->interruptValues[2] = pLynxFWIMData->interruptValues[3];
- pLynxFWIMData->interruptValues[3] = interruptStatus;
-
- #endif
-
- // Check for each type of supported interrupt.
- if (interruptStatus & kLynxINT_PEND)
- {
- // Check for link interrupt. Could be a reset, must do that first
- if (interruptStatus & kLynxP1394_INT)
- LynxFWIMHandleLinkInterrupt (pLynxFWIMData);
-
- // Check for DMA 0 PCL interrupt.
- if (interruptStatus & (kLynxDMA0_PCL | kLynxDMA0_HLT))
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 0);
-
- // Check for DMA 1 PCL interrupt.
- if (interruptStatus & (kLynxDMA1_PCL | kLynxDMA1_HLT))
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 1);
-
- // Check for DMA 2 PCL interrupt.
- if (interruptStatus & (kLynxDMA2_PCL | kLynxDMA2_HLT))
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 2);
-
- // Check for DMA 3 PCL interrupt.
- if (interruptStatus & (kLynxDMA3_PCL | kLynxDMA3_HLT))
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 3);
-
- // Check for DMA 4 PCL interrupt.
- if (interruptStatus & (kLynxDMA4_PCL | kLynxDMA4_HLT))
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 4);
-
- }
-
- // Clear the interrupts. (!!! does this inadvertantly clear interrupts which we have not enabled?)
- // !!! should we only clear those interrupts we know are enabled or do we just not care about the
- // other possible interrupts since we aren't using them anyway?
-
- pLynxRegs->pciInterruptStatus = interruptStatusLittleEndian;
- SynchronizeIO ();
-
- // Did we actually see an interrupt from our hardware? We only count those that are enabled and
- // might actually cause an interrupt. This is still wrong because if we are doing interrupt polling
- // we might have cleared the interrupt while interrupt services was walking the tree. If we report
- // that we didn't handle the interrupt bad things (like a hang) can happen!!!
-
- if( interruptStatus & pLynxFWIMData->interruptMask )
- return (true);
- else
- return (false);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHandleDMAInterrupt
- //
- // This proc handles interrupts sent by PCLs. What kind of processing to do is
- // left to the deferred task which figures this out by indexing into the DMAInfo
- // structure with the dmaChannel parameter
- //
-
- static void LynxFWIMHandleDMAInterrupt(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 dmaChannel )
- {
- OSStatus status = noErr;
-
- if (!(pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled))
- {
- status = FWScheduleDeferredTask (pLynxFWIMData->DMAInfo[dmaChannel].lynxDT, (void *)dmaChannel);
-
- if (status == noErr)
- pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled = true;
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHandleLinkInterrupt
- //
- // This proc handles 1394-specific interrupts (bus reset, GRF overflow).
- //
-
- static UInt32 flushCount = 0;
-
- static void LynxFWIMHandleLinkInterrupt(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxRegistersPtr pLynxRegs;
- UInt32 interrupt, interruptLittleEndian, mask;
- UInt32 handled = 0;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptStatus,
- (UInt32 *) &interruptLittleEndian ) )
- return;
-
- interrupt = EndianSwapImm32Bit (interruptLittleEndian);
-
- // Mask out disabled interrupts.
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptEnable,
- (UInt32 *) &mask ))
- return;
- mask = EndianSwap32Bit (mask) | kLynxLINK_INT;
- interrupt &= mask;
-
- // Check for each type of supported interrupt.
- if (interrupt & kLynxLINK_INT)
- {
- // Check for reset interrupt.
- if (interrupt & kLynxPHY_BUSRESET)
- {
- LynxFWIMHandleResetInterrupt (pLynxFWIMData);
- }
-
- // Check for phy register interrupt.
- if (interrupt & kLynxPHY_REG_RCVD)
- {
- LynxFWIMHandlePhyRegRcvdInterrupt (pLynxFWIMData,interrupt);
- }
-
- // Check for GRF overflow interrupt.
- if ((interrupt & kLynxGRF_OVER_FLOW) ||
- (interrupt & kLynxSNTRJ))
- {
- // This needs work, and its own function. Redoing the DMA prep may take too long, too.
- //zzz do we really need to do anything with GRF overflow.
- //zzz flushing the GRF seems to only cause problems.
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMHandleLinkInterrupt - GRF OVERFLOW ###");
- }
-
- #ifdef LynxFireBug
- if (!(interrupt & kLynxPHY_BUSRESET))
- {
- LynxFWIMHandleMiscInterrupt (pLynxFWIMData);
- }
- #endif
- }
-
- // Clear the interrupts.
- LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptStatus,
- (UInt32) interruptLittleEndian );
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHandleResetInterrupt
- //
- // This proc handles bus reset interrupts.
- //zzz must be able to handle two resets happening before we process one.
- //
-
- static void LynxFWIMHandleResetInterrupt(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // When we get a reset interrupt, the async transmitter and receiver have been disabled.
- // We can't accept (or ack) packets until we know our new node number, and that won't
- // happen until about 150 microseconds from now, when we get the PHY REG RCVD interrupt.
- // We can't enable the receiver until we know this number, because if we do, we'll send
- // acks to packets directed at some other node (if our node ID changed).
-
- // We used to disable the async comparator here but that caused problems if the main
- // receive channel wasn't DMA channel 0 and we were doing some sort of specialized receive
- // on channel 1. The self-ids would come in but we would never get the end of packet token
- // and the PCL would get marked as bad.
-
- // So...
- // In order to prevent acking a packet that isn't ours we leave the receiver disabled until
- // we get the PHY REG RCVD interrupt. When we do we mask the comparator then and enable the
- // async receiver. If we then see a pending reset interrupt or if one was pending at the time
- // we handled this interrupt (ie they were simultaneous) then we disable the async comparator
- // assuming that we'll get another PHY REG RCVD with the valid node id. This assumes that if
- // a reset interrupt preceeds a PHY REG RCVD interrupt it will in fact prevent the PHY REG RCVD
- // interrupt until the PHY gets a valid node ID.
-
- // Invalidate bus generation number.
- pLynxFWIMData->generationValid = false;
-
- // We know for sure the Node ID is false.
- pLynxFWIMData->phyNodeThoughtValid = false;
-
- // If we were expecting a reset, because we just rewrote the CSR ROM, do two things.
- if (pLynxFWIMData->csrROMUpdateClearWhenDone)
- {
- // OpenHCI only: Flip the Config ROM Mapping Register to a new value:
-
- // Everyone: Tell FSL that a reset has come in to complete the process:
- *(pLynxFWIMData->csrROMUpdateClearWhenDone) = 0;
- SynchronizeIO ();
-
- pLynxFWIMData->csrROMUpdateClearWhenDone = 0; // Don't do it twice
-
- }
-
- // Process the reset.
- status = FWProcessBusReset (pLynxFWIMData->fwimID);
-
- // Schedule deferred task to handle reset.
- if (!(pLynxFWIMData->busResetDTScheduled))
- {
- status = FWScheduleDeferredTask (pLynxFWIMData->busResetDeferredTaskID, nil);
-
- if (status == noErr)
- pLynxFWIMData->busResetDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHandlePhyRegRcvdInterrupt
- //
- // This proc handles phy register receive interrupts.
- // Any time we get register 0, load the nodeID register.
- // This only really matters after a bus reset, but is harmless at other times.
- //
-
- static void LynxFWIMHandlePhyRegRcvdInterrupt(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 interrupt)
- {
- LynxRegistersPtr pLynxRegs;
- AbsoluteTime timeoutAbsolute;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr;
- UInt32 phyData, busNodeID, newNodeID;
- UInt32 interruptLittleEndian;
- UInt32 linkData;
-
- // This happens about 150 microseconds after a bus reset, when the PHY sends
- // register zero automatically. That's when we learn our new node ID, so we
- // interrupt to this function, and load that ID into register 0xF00. Now we
- // can send acks for packets directed at us, so we turn the comparator back
- // on and try to start receiving packets.
-
- // If there has been another bus reset after the PHY interrupt but before we
- // get here, then we'll load a stale value but we can detect this by looking at the
- // link interrupt status register and also its contents when we handled the interrupt
- // in the primary interrupt handler. If we see a reset we can disable the receiver
- // again since we know we'll get back here again soon.
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32 *) &phyData ))
- return;
-
- phyData = EndianSwap32Bit (phyData);
-
- if (((phyData & kLynxPHY_REGRD_ADR) >> kLynxPHY_REGRD_ADRPhase) == 0)
- {
-
- // Disable comparator
- LynxFWIMDisableComparators(pLynxFWIMData);
-
- phyData = (phyData & kLynxPHY_REGRD_DAT) >> kLynxPHY_REGRD_DATPhase;
- pLynxFWIMData->lastPhyReg0 = phyData;
-
- // PhysicalID reg is in the same spot for both old and extended PHY...
- newNodeID = (phyData & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &busNodeID ))
- return;
-
- busNodeID = EndianSwap32Bit( busNodeID );
-
- busNodeID &= ~kLynxNODE_ID;
- busNodeID |= (newNodeID << kLynxNODE_IDPhase);
-
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32) EndianSwap32Bit (busNodeID) ))
- return;
-
- // If we got a reset interrupt during this interrupt (ie it was set when we entered the interrupt handler)
- // or if it is set now we make sure to keep the async receiver disabled so we don't ack packets for the wrong
- // node. We check this by looking at the interrupt register now, or'ing it with what was there and checking the
- // reset bit. If there wasn't another reset then turn on the receiver.
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptStatus,
- (UInt32 *) &interruptLittleEndian ))
- return;
-
- interrupt |= EndianSwapImm32Bit (interruptLittleEndian);
-
- if( interrupt & kLynxPHY_BUSRESET ) {
-
- LynxFWIMClearLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
-
- // Since the reset interrupt we saw here may actually be the one which caused this phyregreceived
- // interrupt we set a timer to enable the receiver if we don't see any more resets in the next
- // few milliseconds.
-
- if( pLynxFWIMData->phyNodeThoughtValid ) {
-
- // Cancel any previously pending timers.
- status = CancelTimer (pLynxFWIMData->phyRegTimerID,
- &timeRemaining);
- }
-
- pLynxFWIMData->phyNodeThoughtValid = true;
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (3 * durationMillisecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMDelayedPhyRegReceived,
- pLynxFWIMData,
- &(pLynxFWIMData->phyRegTimerID));
- }
- else {
- LynxFWIMSetLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
- }
-
- // If there hasn't been another reset by now, this will let us receive packets.
- // If there was another reset, the async receiver is disabled, so this does nothing.
-
- LynxFWIMEnableComparators(pLynxFWIMData);
-
- // If there was a bus reset, and we were cycle master, and we aren't any more,
- // we need to turn off the cycle master ASAP in order to avoid PHY jams and to
- // avoid sending duplicate cycle starts.
-
- // Root reg is in the same spot for both old and extended PHY...
- if ((phyData & kLynxPhyR) == 0) // if not root
- {
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkControl,
- (UInt32 *) &linkData ))
- return;
- if (linkData & EndianSwapImm32Bit( kLynxCYCMASTER ))
- {
- // zzz
- // Although this should not conflict with someone setting CYCMASTER,
- // It could conflict with other access to the LinkControl register.
- // Those are rare, but they might re-enable cycle mastering, which is
- // bad. So this should be changed to a race-free method.
-
- // Disable cycle mastering.
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
- }
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDelayedPhyRegReceived
- //
- // Enables the Async transmitter if we think we saw the last in a series of quick
- // resets.
- //
- static OSStatus LynxFWIMDelayedPhyRegReceived(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- LynxRegistersPtr pLynxRegs;
- UInt32 interrupt;
-
- // Get base address of Lynx registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- (*(pLynxFWIMData->interruptDisabler)) (pLynxFWIMData->interruptSetMember,
- (void *) pLynxFWIMData); // >>•••••••>> Ints Off
-
-
- if( pLynxFWIMData->phyNodeThoughtValid ) {
-
- // Disable comparator in case another reset comes in
-
- LynxFWIMDisableComparators(pLynxFWIMData);
-
- // Enable the receiver etc.
- LynxFWIMSetLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
-
- // If we got a reset interrupt while we had interrupts blocked we may have inadvertently re-enabled the
- // receiver. We don't want to enable the comparators if this is true. We check this by looking at the interrupt
- // register. If there wasn't another reset then turn on the comparators.
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkInterruptStatus,
- (UInt32 *) &interrupt ))
- return( accessErr ); // !!! Error message?
-
- interrupt = EndianSwap32Bit( interrupt );
-
- if( !( interrupt & kLynxPHY_BUSRESET) ) {
- LynxFWIMEnableComparators(pLynxFWIMData);
- }
-
- }
-
- (*(pLynxFWIMData->interruptEnabler)) (pLynxFWIMData->interruptSetMember,
- (void *) pLynxFWIMData); // <<•••••••<< Ints On
-
- pLynxFWIMData->phyNodeThoughtValid = false;
-
- return( noErr );
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHandleMiscInterrupt
- //
- // This proc handles miscellaneous interrupts.
- // This is only called #ifdef LynxFireBug
- // zzz no mechanism to prevent race condition in reporting.
- //
-
- static void LynxFWIMHandleMiscInterrupt(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- UInt32 intStatus;
- UInt32 intEnable;
- OSStatus status = noErr;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxFWIMData->pLynxRegisters->linkInterruptStatus,
- (UInt32 *) &intStatus ))
- return;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxFWIMData->pLynxRegisters->linkInterruptEnable,
- (UInt32 *) &intEnable ))
- return;
-
- pLynxFWIMData->miscInterrupt = EndianSwap32Bit ( intStatus & intEnable );
-
- // Schedule deferred task.
- if ((pLynxFWIMData->miscInterrupt) && !(pLynxFWIMData->miscInterruptDTScheduled))
- {
- status = FWScheduleDeferredTask (pLynxFWIMData->miscInterruptDeferredTaskID, nil);
-
- if (status == noErr)
- pLynxFWIMData->miscInterruptDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMResetBus
- //
- // This routine initiates a bus reset.
- //
-
- static OSStatus LynxFWIMResetBus(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- #ifdef LynxFireBug
- sprintf (fireBug, "LynxFWIM: Bus reset from FSL");
- LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
- #endif
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get base address of Lynx registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- // Stripped out a bunch of stuff related to PHY Jams on pre REV A parts.
- // The condition was apparently caused by doing a DV Transmit and a CCM
- // receive at the same time while moving the mouse.
- // Now we just issue the reset.
-
- // Issue the reset. IBR reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
- phyReg |= kLynxPhyIBR;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetContenderBit
- //
- // This routine sets the contender bit in the self ID on the next bus reset.
- //
-
- static OSStatus LynxFWIMSetContenderBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 lynxReg;
- OSStatus status = noErr;
- UInt32 phyReg;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
-
- if( pLynxFWIMData->phyNotPowered )
- status = paramErr; // Fake FSL into loading us even if this doesn't work
- else {
- if( pLynxFWIMData->extendedPhyRegs ) {
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
- phyReg |= kLynxExtPhyCntd;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
- }
- else {
- // Program the contender bit to be set on next reset.
- //zzz ought to have routine for setting gpios.
- lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
- lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
- pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
- SynchronizeIO ();
- pLynxRegs->gpioData[1] = EndianSwapImm32Bit (1);
- SynchronizeIO ();
- }
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMClearContenderBit
- //
- // This routine clears the contender bit in the self ID on the next bus reset.
- //
-
- static OSStatus LynxFWIMClearContenderBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 lynxReg;
- OSStatus status = noErr;
- UInt32 phyReg;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
- else {
- if( pLynxFWIMData->extendedPhyRegs ) {
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
- phyReg &= ~kLynxExtPhyCntd;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
- }
- else {
- // Program the contender bit to be clear on next reset.
- //zzz ought to have routine for setting gpios.
- lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
- lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
- pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
- SynchronizeIO ();
- pLynxRegs->gpioData[1] = EndianSwapImm32Bit (0);
- SynchronizeIO ();
- }
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMEnableCycleMaster
- //
- // This routine enables cycle mastering.
- // Unlike the disable routine below, which is somewhat redundant, this routine
- // is the only place we set cycle master. Setting cycle master is done only
- // after the IRM assigns a new cycle master, which is rare and isn't supposed
- // to be particularly fast. (ie, cycle loss is OK)
- //
- // zzz should there be a mechanism to report failure, such as FSL asked us to
- // become cyclemaster, but by the time we got here, we aren't root anymore?
- //
-
- static OSStatus LynxFWIMEnableCycleMaster(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- // Enable cycle mastering if we're root.
- if ( !status && pLynxFWIMData->root)
- {
- // For safety, double-check that we're root: Root reg is in the same spot for both old and extended PHY...
- if (((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR)
- {
- LynxFWIMSetLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
-
- // And now, if we lost root, we may have screwed up linkControl.
- // This isn't perfect, but at least turn off the CYCMASTER
-
- if (!(((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR))
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
- }
- }
-
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDisableCycleMaster
- //
- // This routine disables cycle mastering.
- // Note, this is somewhat redundant, because we will have turned off cycle
- // mastering at primary interrupt level as soon as we lose root status. The
- // only case in which this function would really do anything is if FSL wanted
- // to stop being the cycle master even though we are the root node.
- //
-
- static OSStatus LynxFWIMDisableCycleMaster(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- // Disable cycle mastering.
- if( !status ) {
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetRootHoldoffBit
- //
- // This routine sets the PHY root holdoff bit.
- //
-
- static OSStatus LynxFWIMSetRootHoldoffBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Set the root holdoff bit in the PHY. RHB reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
- phyReg |= kLynxPhyRHB;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMClearRootHoldoffBit
- //
- // This routine clears the PHY root holdoff bit.
- //
-
- static OSStatus LynxFWIMClearRootHoldoffBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Clear the root holdoff bit in the PHY. RHB reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
- phyReg &= ~kLynxPhyRHB;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMGetUniqueID
- //
- // This routine returns the local unique ID.
- //
-
- static OSStatus LynxFWIMGetUniqueID(
- FWIMGetUniqueIDParamsPtr pFWIMGetUniqueIDParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMGetUniqueIDParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- if( !status ) {
- if (pLynxFWIMData->eepromValid)
- {
- pFWIMGetUniqueIDParams->uniqueID.hi = pLynxFWIMData->eepromInfo.busInfoBlock[2];
- pFWIMGetUniqueIDParams->uniqueID.lo = pLynxFWIMData->eepromInfo.busInfoBlock[3];
- }
- else
- {
- //zzz Fake it
- pFWIMGetUniqueIDParams->uniqueID.hi = 'lynx';
- pFWIMGetUniqueIDParams->uniqueID.lo = (UInt32) pLynxFWIMData;
- }
- }
-
- // sprintf (debugStr, "LynxFWIMGetUniqueID : Node Vendor ID %06lx Chip ID %02lx%08lx",
- // (long) pFWIMGetUniqueIDParams->uniqueID.hi >> 8,
- // (long) pFWIMGetUniqueIDParams->uniqueID.hi & 0xff,
- // (long) pFWIMGetUniqueIDParams->uniqueID.lo);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSendLinkOnPacket
- //
- // This proc sends the given link on packet.
- //
-
- static OSStatus LynxFWIMSendLinkOnPacket(
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- UInt32 linkOnData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Set up link on data.
- if (status == noErr)
- {
- linkOnData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
- linkOnData &= ~kFWPhyPacketID;
- linkOnData |= kFWLinkOnPacketID << kFWPhyPacketIDPhase;
- }
-
- // Send packet.
- if (status == noErr)
- {
- LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
- linkOnData, ~linkOnData, 0, 0, 0, 0);
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSendPhyConfigurationPacket
- //
- // This proc sends the given Phy configuration packet.
- //
-
- static OSStatus LynxFWIMSendPhyConfigurationPacket(
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- UInt32 configurationData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Set up phy configuration data.
- if (status == noErr)
- {
- configurationData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
- configurationData &= ~kFWPhyPacketID;
- configurationData |= kFWConfigurationPacketID << kFWPhyPacketIDPhase;
- }
-
- // Send packet.
- if (status == noErr)
- {
- LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
- configurationData, ~configurationData, 0, 0, 0, 0);
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetCSRROM
- //
- // In an OpenHCI FWIM, this routine would activate a new CSR ROM image
- // using the hardware map. Lynx can't do that, so we just cause a bus
- // reset instead. This is provided largely as a sample to show what to
- // to for OpenHCI. We do go through all the "motions" of OHCI.
- //
-
- static OSStatus LynxFWIMSetCSRROM(
- FWIMSetCSRROMParamsPtr pFWIMSetCSRROMParams,
- UInt32 *pCommandAcceptance)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSetCSRROMParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Can't return an error from this guy or FWIM won't load. If the bus comes alive again
- // we'll issue a reset anyway.
- if( !pLynxFWIMData->phyNotPowered ) {
-
- // If this was an OpenHCI FWIM, we would copy the ROM image into a private
- // buffer that we have already mapped (not the active one, a second buffer).
- // The new ROM is at pFWIMSetCSRROMParams->pCSRROM and it has a length
- // of pFWIMSetCSRROMParams->length, which we ignore for now and is always 1024.
- // In theory we then do a CheckPointIO (kMoreIO). Then we set an internal flag
- // indicating special treatment for the next bus reset. The flag is equal to
- // the pointer FSL gave us:
-
- pLynxFWIMData->csrROMUpdateClearWhenDone = pFWIMSetCSRROMParams->clearWhenDone;
-
- // Next, both Lynx and OpenHCI cause a bus reset:
-
- if (status == noErr) {
- // Issue a reset. IBR reg is in the same spot for both old and extended PHY...
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
- phyReg |= kLynxPhyIBR;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
- }
-
- // Now, OpenHCI will do some more work. But not here, it's in the Bus Reset
- // Interrupt handler (LynxFWIMHandleResetInterrupt): As soon as the bus reset
- // actually comes in, store a new value in the Config ROM Mapping Register
- // (section 5.5.6), and also immediately copy new values into the Config ROM
- // Header Register (5.5.2) and the Bus Options Register (5.5.4). Then tell FSL
- // that the requested work is done. Once this is done, immediately cause
- // *another* bus reset.
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDoLocalCompareSwap
- //
- // This routine does a Compare/Swap on a hardware-supported bus management
- // register. This is never called for LynxFWIM because we don't report that
- // feature. This is just sample code for OpenHCI. But, note that any FWIM
- // that reports version 1.1 or above must have a dispatch table entry for this.
- //
-
- static OSStatus LynxFWIMDoLocalCompareSwap(
- FWIMCompareSwapParamsPtr pFWIMCompareSwapParams)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMCompareSwapParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if (status == noErr) {
- //OpenHCI would immediatly use the Bus Management CSR Registers (5.5.1)
- //to perform the requested action:
-
- //The OHCI spec doesn't say this clearly, but a compare/swap should be
- //very fast, and is not supposed to fail.
-
- //The steps go something like this (don't forget endian swaps...):
- // Load csrData with pFWIMCompareSwapParams->oldValue
- // Load csrCompare with pFWIMCompareSwapParams->newValue
- // Load csrSel with pFWIMCompareSwapParams->targetRegister
- // Poll for csrDone (slowly - don't hammer the chip if it's in the middle of DMA.
- // for example, do 5 SynchronizeIO()'s between polls.)
- // Load pFWIMCompareSwapParams->returnValue with csrData
-
- // It might be wise to time out on csrDone after 0.01ms or so and set returnValue to ~oldValue,
- // (inverse of oldValue) which indicates failure, just in case somehow the chip ignores the request.
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetAsynchFilters
- //
- // In an OpenHCI FWIM, this routine attempts to set both the asynch request
- // filters (5.13.1) and the physical request filters (5.13.2). Other FWIMs
- // that have physical capability could also honor these requests. This
- // dispatch entry is required, regardless of the support level, in any FWIM
- // that reports version 1.1 or higher.
- //
- // In OpenHCI, the filters can be changed by a bus reset. This call should
- // simply attempt to set the filters as requested, then return the actual
- // values. Multiple attempts should not be made (FSL will fix things up
- // after a bus reset).
-
- static OSStatus LynxFWIMSetAsynchFilters(
- FWIMSetAsynchFiltersParamsPtr pFWIMSetAsynchFiltersParams)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSetAsynchFiltersParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // If the PHY is not powered, we'll get a bus reset before any further asynch
- // traffic. So the settings don't matter, and we can just return.
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if (status == noErr) {
- // OpenHCI would do it kind of like this:
- //pOHCI->AsynchSetHi = pFWIMSetAsynchFiltersParams->asynchFilterHi;
- //pOHCI->AsynchClearHi = ~pFWIMSetAsynchFiltersParams->asynchFilterHi;
- //... repeat for Lo and Physical
-
- //Now return filter values:
- //pFWIMSetAsynchFiltersParams->asynchFilterHi = pOHCI->AsynchSetHi;
- //... etc.
-
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetFWIMState
- //
- // Puts the FWIM to sleep or wakes it back up again.
- // For Idle and Sleep we need to insure we will not ever call the FSL until
- // we are make active or standby again. This is so the FSL can be fovr'd
- // from "ROM" and not get called while in the process of getting replaced.
- // Eventually we will use this call to save power by turning FWIMs
- // off.
- //
-
- static OSStatus LynxFWIMSetFWIMState(
- FWIMSetFWIMStateParamsPtr pFWIMSetFWIMStateParams)
- {
-
- LynxFWIMDataPtr pLynxFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSetFWIMStateParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // What do we do here if we are being asked to go to sleep? Nothing? !!!
- //if( pLynxFWIMData->phyNotPowered )
- // status = accessErr; // !!! Proper error?
-
- switch( pFWIMSetFWIMStateParams->fwimState ) {
-
- case kFWIMActive:
- case kFWIMStandby:
- // Try to make the FWIM active if we need to.
-
- if( pLynxFWIMData->phyNotPowered ) {
-
- LynxFWIMAttemptPHYWakeup( (void *)pLynxFWIMData, nil );
-
- // If we couldn't wakeup then the PHY is not powered.
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr;
- }
-
- break;
-
- case kFWIMIdle:
- case kFWIMSleep:
- // With one of these guys we need to quiesce the FWIM. Since
- // for a LynxFWIM this is the same thing as operating without PHY
- // power we'll just pretend we have an umpowered PHY until told otherwise.
-
- LynxFWIMWaitForPHYPower(pLynxFWIMData,true);
- break;
-
- default:
- status = paramErr;
- break;
-
- }
-
-
- return( status );
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMGetCycleTime
- //
- // This routine returns the current value of the cycle timer register.
- //
-
- static OSStatus LynxFWIMGetCycleTime(
- FWIMGetCycleTimeParamsPtr pFWIMGetCycleTimeParams)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMGetCycleTimeParams->fwimCommandParams.fwimSpecificData;
-
- if (pLynxFWIMData->phyNotPowered)
- status = accessErr; // !!! Proper error?
-
- if (status == noErr)
- *(pFWIMGetCycleTimeParams->pCycleTime) =
- EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->cycleTimer);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWritePhyRegister
- //
- // This proc writes data to the specified phy register.
- //
-
- static void LynxFWIMWritePhyRegister(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 regAddress,
- UInt8 regData)
- {
- LynxRegistersPtr pLynxRegs;
- UInt32 phyChipAccess;
- UInt32 patience;
- UInt32 phyData;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister");
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32 *) &phyData ) )
- return;
-
- if (phyData & EndianSwapImm32Bit (kLynxWRPHY))
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister - write bit already set!!!");
-
- // Set up phyChipAccess to write phy.
- // Set the write bit, the register address, and data.
- phyChipAccess = kLynxWRPHY;
- phyChipAccess |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
- phyChipAccess |= (regData << kLynxPHY_REG_DATPhase) & kLynxPHY_REG_DAT;
-
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32) EndianSwap32Bit (phyChipAccess) ))
- return;
-
- patience = 100000;
- while (patience-- )
- {
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32 *) &phyData ))
- return;
-
- if( !(phyData & EndianSwapImm32Bit (kLynxWRPHY)) )
- break; // Done
-
- if (!patience)
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister: waited too long");
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReadPhyRegister
- //
- // This proc reads data from the specified phy register.
- // This has the side effect of triggering a PHY received interrupt,
- // which should be harmless.
- // zzz Still need to make the timeouts use real time, not CPU clocks.
- //
-
- static UInt8 LynxFWIMReadPhyRegister(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt8 regAddress)
- {
- LynxRegistersPtr pLynxRegs;
- UInt32 phyChipAccess,
- phyChipAccessRead;
- UInt8 returnedAddress;
- UInt8 regData;
- UInt32 patience;
- UInt32 phyData;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister");
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Set up phyChipAccess register to read phy.
- // Set read bit, register address, and set returned read address to an
- // invalid phy address, so we can tell when it changes.
- phyChipAccessRead = kLynxRDPHY;
- phyChipAccessRead |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
- phyChipAccessRead |= (kLynxPhyInvalidAddress << kLynxPHY_REGRD_ADRPhase) &
- kLynxPHY_REGRD_ADR;
-
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32) EndianSwap32Bit (phyChipAccessRead) ))
- return( 0 );
-
- // Wait for the desired return read address.
- // Tests show that this typically takes 10 microseconds,
- // though I have seen it take up to 330 microseconds.
- // Of course, if the card has wedged, this will take forever.
- do
- {
- // Wait for read to be sent.
- patience = 2000;
- while (patience-- )
- {
- UInt32 wait = 2000;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32 *) &phyData ))
- return( 0 );
-
- if( !(phyData & EndianSwapImm32Bit (kLynxRDPHY)) )
- break; // Done
-
- while (wait--) SynchronizeIO();
- if (!patience)
- {
- if (NoPhyReset)
- {
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, but cannot reset right now");
- return 0;
- }
- else
- {
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, full card reset");
- LynxFWIMFullReset();
- }
- }
- }
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32 *) &phyChipAccess ))
- return( 0 );
- phyChipAccess = EndianSwap32Bit (phyChipAccess);
-
- // Read returned address.
- returnedAddress = (phyChipAccess & kLynxPHY_REGRD_ADR) >>
- kLynxPHY_REGRD_ADRPhase;
-
- // If RDPHY still set, make sure we don't accept the value
- if (phyChipAccess & kLynxRDPHY)
- returnedAddress = 0xfff;
-
- // If returned address is not what we we're looking for and not what
- // we set it to, start another read.
- if ((returnedAddress != regAddress) &&
- (returnedAddress != kLynxPhyInvalidAddress))
- {
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->phyControl,
- (UInt32) EndianSwap32Bit (phyChipAccessRead) ))
- return(0);
- }
- } while (returnedAddress != regAddress);
-
- // Extract and return phy register contents.
- regData = (phyChipAccess & kLynxPHY_REGRD_DAT) >>
- kLynxPHY_REGRD_DATPhase;
- return regData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPrepareAsyncDMA
- //
- // This proc perpares PCLs for async receive and primes the DMA.
- //
-
- static void LynxFWIMPrepareAsyncDMA(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 channel)
- {
- // Create the async receive PCL program.
- LynxFWIMCreateAsyncRxPCLProgram (pLynxFWIMData);
-
- // Start async receive PCL program.
- LynxFWIMStartAsyncRxPCLProgram
- (pLynxFWIMData, &(pLynxFWIMData->asyncPCL[kAsyncRxFirstPacketPCL]));
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddAsyncRxPCL
- //
- // This proc adds a PCL to the active async receive PCL list.
- //
-
- static void LynxFWIMAddAsyncRxPCL(
- LynxPCLPtr pPCL)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData,
- pPrevLynxAsyncRxPCLData,
- pOverflowLynxAsyncRxPCLData;
- LynxPCLPtr pPrevPCL,
- pOverflowPCL;
-
- // Get PCL data and Lynx FWIM data for PCL to add.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pLynxFWIMData = pLynxAsyncRxPCLData->pLynxFWIMData;
-
- // Get PCL and PCL data for overflow handling.
- pOverflowPCL = pLynxFWIMData->asyncRxOverflowPCLSegment;
- pOverflowLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pOverflowPCL->refCon;
-
- // Link new PCL to overflow handler and invalidate new PCL's status.
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pOverflowLynxAsyncRxPCLData->pPCLPhysical);
- pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
- pLynxAsyncRxPCLData->pNextPCL = nil;
-
- // Get last async receive PCL.
- pPrevPCL = pLynxFWIMData->pLastAsyncPCL;
-
- // Link new PCL to last one.
- if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncPCL != nil))
- {
- pPrevPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
- pPrevLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPrevPCL->refCon;
- pPrevLynxAsyncRxPCLData->pNextPCL = pPCL;
- }
- else
- {
- pLynxFWIMData->pNextAsyncPCL = pPCL;
- }
-
- // Check for overflow.
- if (pLynxFWIMData->asyncRxOverflowFlag)
- {
- // Restart async receive PCL program at new PCL if it's still unused.
- if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
- LynxFWIMStartAsyncRxPCLProgram (pLynxFWIMData, pPCL);
- }
-
- // New PCL is now last.
- pLynxFWIMData->pLastAsyncPCL = pPCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncRxPCLProgram
- //
- // This proc creates the async receive PCL program.
- //
-
- static void LynxFWIMCreateAsyncRxPCLProgram(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxFWIMDataPtr pPhysLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- LynxPCLPtr pPCL;
- UInt32 pclNum,
- packetNum;
-
- // Get pointer to link registers and physical pointer to FWIM data.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
- pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
-
- // Create dummy PCL for starting.
- LynxFWIMCreateAsyncRxDummyPCL (pLynxFWIMData);
-
- // Create overflow segment.
- LynxFWIMCreateAsyncRxOverflowPCLSegment (pLynxFWIMData);
-
- // Create packet PCLs.
- for (pclNum = kAsyncRxFirstPacketPCL, packetNum = 0;
- pclNum <= kAsyncRxLastPacketPCL;
- pclNum++, packetNum++)
- {
- // Get pointer to PCL.
- pPCL = &(pLynxFWIMData->asyncPCL[pclNum]);
-
- // Add PCL data record.
- pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[pclNum]);
- pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncRxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncPCLPhys + (pclNum * sizeof (LynxPCL));
- pLynxAsyncRxPCLData->packetBuffer = pLynxFWIMData->asyncBuf[packetNum];
- pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
-
- // Initialize PCL header.
- pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
-
- // Set up PCL buffers.
- pPCL->buffer[0].control =
- EndianSwapImm32Bit ((kLynxDMA_RCV << kLynxDMA_CMDPhase) |
- kLynxDMA_LAST_BUF |
- kPacketBufferSize |
- kLynxDMA_INT);
- pPCL->buffer[0].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncBufPhys[packetNum]);
-
- // Add PCL to program.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncRxDummyPCL
- //
- // This proc creates a dummy PCL for starting the async receive PCL program.
- //
-
- static void LynxFWIMCreateAsyncRxDummyPCL(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- LynxPCLPtr pPCL;
-
- // Just fill in the basics.
- pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
- pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxDummyPCL]);
- pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncRxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncPCLPhys + (kAsyncRxDummyPCL * sizeof (LynxPCL));
- pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncRxOverflowPCLSegment
- //
- // This proc creates the async receive overflow PCL segment.
- //zzz what should happen if we get to end of list?
- //
-
- static void LynxFWIMCreateAsyncRxOverflowPCLSegment(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxFWIMDataPtr pPhysLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- LynxPCLPtr pPCL;
-
- // This PCL goes at the end of the async receive PCL program. If we run out
- // of async receive PCLs, we want to do a controlled shutdown so that we send
- // the right ack code on any future packets (ack_busyX). So this PCL sets a
- // bit that causes ack_busyX for all packets. That way, packets don't pile up
- // in the GRF.
-
- // At present, some packets could be in the FIFO by the time we set the busyX
- // bit. Those packets will linger there until we recover, and they will
- // block any incoming isoch packets. That's not good. We should add more PCLs
- // after this one that will drain the FIFO (but not bitbucket the packets).
-
- // By leaving the comparator enabled, we send busyX, which hopefully will buy
- // us some time. Here's a rundown of how Lynx determines ack values:
-
- // After a bus reset, the async receiver is disabled. We don't ack any packet.
- // If the Async receiver is enabled, then each packet is checked against the
- // nodeID set in register 0xF00. Packets for other nodes are ignored.
- //
- // If the incoming packet matches our node ID, then...
- // If there is no comparator enabled that matches the packet, send no ack.
- // [A Lynx at the other end will see a Link Timeout]
- // If there is a comparator enabled that matches the packet...
- // If the busy bit in register 0xF04 is set, send ack_busyX
- // If not, try to receive the packet...
- // If there is a FIFO overflow, send ack_busyX
- // If there is a CRC error, send ack_dataErr (probably. Very rare)
- // If we're still OK...
- // If it's a broadcast packet, send no ack.
- // If it's a write and the comparator has WRITE_REQ_ACK_SEL, send ack_complete
- // Otherwise send ack_pending
-
- // Note that we do set WRITE_REQ_ACK_SEL so that we won't have to send a write
- // response later. This is why any packets left over in the FIFO after we run
- // out of PCLs must still be received - if we sent ack_complete, and they are
- // write requests, we must not throw them away. We already said we took care of them.
-
- // Get pointer to link registers and physical pointer to FWIM data.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
- pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
-
- // Set up PCL to busy incoming packets.
- //zzz should be a little cleaner
- pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxOverrunPCL]);
- pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxOverrunPCL]);
- pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncRxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncPCLPhys + (kAsyncRxOverrunPCL * sizeof (LynxPCL));
- pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
- pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
- pPCL->remaining = EndianSwapImm32Bit (0);
- pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
-
- // If we leave the comparator enabled, but set this busy bit, then we'll
- // send ack_busyX to all inbound async packets. If we turn the comparator
- // off too (like we used to) then we won't ack packets at all, which may
- // confuse the sender.
-
- // Set link to busy all async packets.
- pPCL->buffer[0].control = EndianSwapImm32Bit (kLynxDMA_LOAD << kLynxDMA_CMDPhase);
- pPCL->buffer[0].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowSetLinkControl));
- pPCL->buffer[1].control =
- EndianSwapImm32Bit (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase);
- pPCL->buffer[1].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxRegs->linkControl)); // !!! if accessing the link control register fails, how do we tell?
-
- // Historical note - we used to turn off the comparator. That prevents the
- // bit for sending ack_busyX from working and causes us to send no ack. So
- // we don't do that anymore.
-
- // Set overflow flag so software knows this happened
- pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
- pPCL->buffer[2].control =
- EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
- pPCL->buffer[2].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowFlag));
-
- // Set PCL segment in FWIM data.
- pLynxFWIMData->asyncRxOverflowPCLSegment = pPCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartAsyncRxPCLProgram
- //
- // This proc starts the async receive PCL program.
- //
-
- static void LynxFWIMStartAsyncRxPCLProgram(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pStartPCL)
- {
- LynxRegistersPtr pLynxRegs;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData,
- pStartLynxAsyncRxPCLData;
- LynxPCLPtr pPCL;
- Boolean asyncRxReady = false;
-
- // Get pointer to link registers and start PCL's data.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Check for overflow.
- if (pLynxFWIMData->asyncRxOverflowFlag)
- {
- // Check if we've started priming.
- if (pLynxFWIMData->numAsyncRxPCLsPrimed == 0)
- {
- pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
- pLynxFWIMData->numAsyncRxPCLsPrimed = 1;
- }
- else
- {
- pLynxFWIMData->numAsyncRxPCLsPrimed++;
- }
-
- // Check if we've primed enough receive PCLs.
- if (pLynxFWIMData->numAsyncRxPCLsPrimed >= kLynxNumAsyncRxPCLsToPrime)
- {
- pLynxFWIMData->asyncRxOverflowFlag = 0;
- pLynxFWIMData->numAsyncRxPCLsPrimed = 0;
- asyncRxReady = true;
- }
- }
- else
- {
- // We're ready to receive.
- pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
- asyncRxReady = true;
- }
-
- if (asyncRxReady)
- {
- // Quiet the DMA channel.
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].control = EndianSwapImm32Bit (0);
- SynchronizeIO();
-
- // Start the PCL program at the given PCL.
- pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
- pStartLynxAsyncRxPCLData =
- (LynxAsyncRxPCLDataPtr) pLynxFWIMData->pStartAsyncRxPCL->refCon;
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncRxPCLData->pPCLPhysical);
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].curPCLAddr =
- EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
- SynchronizeIO();
-
- // Note, not clear that the ready register really matters here
-
- // Enable the DMA.
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].ready = EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
- SynchronizeIO();
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO();
-
- // Really only need to do this once
-
- // Enable comparator.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask0,
- (UInt32) EndianSwapImm32Bit (kLynxAsynctCodeNormal << kLynxCMP0_FIELD3_MASKPhase)))
- return;
-
- LynxFWIMSetAsyncRxComparatorMask1
- (pLynxFWIMData,
- kLynxRCV_SELF_ID_EN |
- kLynkDEST_ID_SEL_BusNode |
- kLynxEN_CH_COMPARE |
- kLynxWRITE_REQ_ACK_SEL);
-
- // Clear busy flag in linkControl.
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxBUSY_CNTRL ));
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddAsyncTxPCL
- //
- // This proc adds a PCL to the active async transmit PCL list.
- //
-
- static void LynxFWIMAddAsyncTxPCL(
- LynxPCLPtr pPCL)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxAsyncTxPCLDataPtr pLynxAsyncTxPCLData,
- pPrevLynxAsyncTxPCLData,
- pDoneLynxAsyncRxPCLData;
- LynxPCLPtr pPrevPCL,
- pDonePCL;
-
- // Get PCL data and Lynx FWIM data for PCL to add.
- pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
- pLynxFWIMData = pLynxAsyncTxPCLData->pLynxFWIMData;
-
- // Get PCL and PCL data for done handling.
- pDonePCL = pLynxFWIMData->asyncTxDonePCLSegment;
- pDoneLynxAsyncRxPCLData = (LynxAsyncTxPCLDataPtr) pDonePCL->refCon;
-
- // Link new PCL to done handler and invalidate new PCL's status.
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
- pLynxAsyncTxPCLData->pNextPCL = nil;
- pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
-
- // Get last async transmit PCL.
- pPrevPCL = pLynxFWIMData->pLastAsyncTxPCL;
-
- // Link new PCL to last one.
- if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncTxPCL != nil))
- {
- pPrevPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
- pPrevPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);//zzz is this the best?
- pPrevLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPrevPCL->refCon;
- pPrevLynxAsyncTxPCLData->pNextPCL = pPCL;
- }
- else
- {
- pLynxFWIMData->pNextAsyncTxPCL = pPCL;
- }
-
- // Check for asynchronous transmit done.
- if (pLynxFWIMData->asyncTxDoneFlag)
- {
- // Restart async transmit PCL program at new PCL if it's still unused.
- if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
- LynxFWIMStartAsyncTxPCLProgram (pLynxFWIMData, pPCL);
- }
-
- // New PCL is now last.
- pLynxFWIMData->pLastAsyncTxPCL = pPCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncTxDummyPCL
- //
- // This proc creates a dummy PCL for starting the async transmit PCL program.
- //
-
- static void LynxFWIMCreateAsyncTxDummyPCL(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxAsyncTxPCLDataPtr pLynxAsyncTxPCLData;
- LynxPCLPtr pPCL;
-
- // Just fill in the basics.
- pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
- pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDummyPCL]);
- pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncTxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDummyPCL * sizeof (LynxPCL));
- pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncTxDonePCLSegment
- //
- // This proc creates the async transmit done PCL segment.
- //
-
- static void LynxFWIMCreateAsyncTxDonePCLSegment(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxFWIMDataPtr pPhysLynxFWIMData;
- LynxAsyncTxPCLDataPtr pLynxAsyncTxPCLData;
- LynxPCLPtr pPCL;
-
- // Get physical pointer to FWIM data.
- pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
-
- // Set up PCL to set done flag.
- pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDonePCL]);
- pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDonePCL]);
- pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncTxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDonePCL * sizeof (LynxPCL));
- pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
- pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
- pPCL->remaining = EndianSwapImm32Bit (0);
- pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
-
- // Set done flag.
- pLynxFWIMData->asyncTxDoneFlag = 0xFFFFFFFF;
- pPCL->buffer[0].control =
- EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
- pPCL->buffer[0].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncTxDoneFlag));
-
- // Set PCL segment in FWIM data.
- pLynxFWIMData->asyncTxDonePCLSegment = pPCL;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCreateAsyncTxDataPCL
- //
- // This proc creates a data PCL for the async transmit PCL program.
- //
-
- static void LynxFWIMCreateAsyncTxDataPCL(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxAsyncTxPCLDataPtr pLynxAsyncTxPCLData;
- LynxPCLPtr pPCL;
-
- // Just fill in the basics.
- pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]);
- pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL]);
- pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
- pLynxAsyncTxPCLData->pPCLPhysical =
- pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDataPCL * sizeof (LynxPCL));
- pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartAsyncTxPCLProgram
- //
- // This proc starts the async transmit PCL program.
- //
-
- static void LynxFWIMStartAsyncTxPCLProgram(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pStartPCL)
- {
- LynxRegistersPtr pLynxRegs;
- LynxAsyncTxPCLDataPtr pLynxAsyncTxPCLData,
- pStartLynxAsyncTxPCLData;
- LynxPCLPtr pPCL;
- Boolean asyncTxReady = false;
-
- // Clear done flag.
- pLynxFWIMData->asyncTxDoneFlag = 0;
-
- // Get pointer to link registers and start PCL's data.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Quiet the DMA channel.
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].control = EndianSwapImm32Bit (0);
- SynchronizeIO();
-
- // Start the PCL program at the given PCL.
- pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
- pStartLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pStartPCL->refCon;
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
- pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].curPCLAddr =
- EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
- SynchronizeIO();
-
- // Enable the DMA.
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].ready =
- EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
- SynchronizeIO();
- pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSafeRegisterRead
- //
- // This proc uses DMA to access a PCI register. This is useful because if
- // the PHY is not powered correctly accesses to Lynx registers at 0xB00 and
- // above will bus error. Since we don't know how to safely recover from this
- // we use DMA for these register accesses. If the DMA bus-errors it just
- // halts which is no problem for us or the user.
- //
- // This makes for some messy code. In particular this function needs to be
- // re-entrant. Also it shares a DMA channel with the asynchronous transmit
- // section. We need to be careful to let whatever that channel was doing
- // finish before we try to use the channel. Finishing means the DMA either
- // stops or the transmitter gets turned off by a reset.
- //
-
- static OSStatus LynxFWIMSafeRegisterRead(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 * registerData )
- {
- LynxRegistersPtr pLynxRegs;
- SInt32 stackPtr;
- LynxPCLPtr pPCL;
- UInt32 waitFlag;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // We don't want to get stepped on if this code gets re-entered. To avoid this each
- // instance gets its own set of PCLs, allocated on a stack. The stack is actually just
- // an index into an array of PCLs.
-
- stackPtr = IncrementAtomic( &pLynxFWIMData->phyRegAccessStack);
- stackPtr <<= 1; // Two PCLs per instance
-
- // Wait for DMA to stop (flag will never get set)
- waitFlag = 0;
- status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, &waitFlag, 0xFFFFFFFF );
-
- if( status )
- goto end; // Turn on read responses? Probably need a reset now anyway
-
- // Setup the PCLs and Buffers as follows:
-
- // PCL[0] Points to PCL[1]
-
- // PCL[1] Points to Invalid PCL (1)
- // Buffer[0] Loads Quad from registerAddress
- // Buffer[1] Stores Quad to Buffer[3].control
- // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
- // Buffer[3] Address Field is the completion flag, Control field is the data.
-
- // Create the DummyPCL
- pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessDummyPCL + stackPtr]);
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
-
-
- // Setup the real PCL that does the work
- pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessPCL + stackPtr]);
-
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) 1);
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) 1);
-
- // Buffer[0] Loads Quad from registerAddress
- pPCL->buffer[0].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_LOAD << kLynxDMA_CMDPhase));
- pPCL->buffer[0].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) registerAddress );
-
- // Buffer[1] Stores Quad to Buffer[3].control
- pPCL->buffer[1].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase));
- pPCL->buffer[1].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].control));
-
- // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
- pPCL->buffer[2].control = EndianSwapImm32Bit ((UInt32) ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF));
- pPCL->buffer[2].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].address) );
-
- pPCL->buffer[3].address = 0;
- pPCL->buffer[3].control = 0; // For consistency if we return an error
-
- // Keep trying to run the program til it succeeds or we notice a reset or timeout condition.
- while( !pPCL->buffer[3].address ) {
-
- // Start the Rx PCL program at the given PCL.
- pLynxRegs->dmaChannel[kDMARegisterAccess].curPCLAddr =
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessDummyPCL + stackPtr]));
- SynchronizeIO();
-
- // Enable the DMA.
- pLynxRegs->dmaChannel[kDMARegisterAccess].ready =
- EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
- SynchronizeIO();
- pLynxRegs->dmaChannel[kDMARegisterAccess].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO();
-
- // Wait for DMA to stop
- status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, (UInt32 *)&pPCL->buffer[3].address, 0xFFFFFFFF );
- if( status )
- goto end; // Turn on read responses? Probably need a reset now anyway
- }
-
- end:
- // Suspend FWIM, wait 5 seconds for power to come back
- if( status )
- LynxFWIMWaitForPHYPower(pLynxFWIMData,false);
- else
- *registerData = pPCL->buffer[3].control;
- DecrementAtomic( &pLynxFWIMData->phyRegAccessStack);
- return(status);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSafeRegisterWrite
- //
- // This proc uses DMA to access a PCI register. This is useful because if
- // the PHY is not powered correctly accesses to Lynx registers at 0xB00 and
- // above will bus error. Since we don't know how to safely recover from this
- // we use DMA for these register accesses. If the DMA bus-errors it just
- // halts which is no problem for us or the user.
- //
- // This makes for some messy code. In particular this function needs to be
- // re-entrant. Also it shares a DMA channel with the asynchronous transmit
- // section. We need to be careful to let whatever that channel was doing
- // finish before we try to use the channel. Finishing means the DMA either
- // stops or the transmitter gets turned off by a reset.
- //
-
- static OSStatus LynxFWIMSafeRegisterWrite(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData )
- {
- LynxRegistersPtr pLynxRegs;
- SInt32 stackPtr;
- LynxPCLPtr pPCL;
- UInt32 waitFlag;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // We don't want to get stepped on if this code gets re-entered. To avoid this each
- // instance gets its own set of PCLs, allocated on a stack. The stack is actually just
- // an index into an array of PCLs.
-
- stackPtr = IncrementAtomic( &pLynxFWIMData->phyRegAccessStack);
- stackPtr <<= 1; // Two PCLs per instance
-
- // Wait for DMA to stop (flag will never get set)
- waitFlag = 0;
- status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, &waitFlag, 0xFFFFFFFF );
- if( status )
- goto end; // Turn on read responses? Probably need a reset now anyway
-
- // Setup the PCLs and Buffers as follows:
-
- // PCL[0] Points to PCL[1]
-
- // PCL[1] Points to Invalid PCL (1)
- // Buffer[0] Loads Quad from registerData as stored in buffer[3].control
- // Buffer[1] Stores Quad to registerAddress
- // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
- // Buffer[3] Address Field is the completion flag
-
- // Create the DummyPCL
- pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessDummyPCL + stackPtr]);
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
-
-
- // Setup the real PCL that does the work
- pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessPCL + stackPtr]);
-
- pPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) 1);
- pPCL->nextPCLAlt =
- (UInt32 *) EndianSwap32Bit ((UInt32) 1);
-
- // Buffer[0] Loads Quad from registerData as stored in buffer[3].control
- pPCL->buffer[0].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_LOAD << kLynxDMA_CMDPhase));
- pPCL->buffer[0].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].control) );
-
- // Buffer[1] Stores Quad to registerAddress
- pPCL->buffer[1].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase));
- pPCL->buffer[1].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) registerAddress );
-
- // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
- pPCL->buffer[2].control = EndianSwapImm32Bit ((UInt32) ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF));
- pPCL->buffer[2].address = (UInt32 *)
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].address) );
-
- pPCL->buffer[3].address = 0;
- pPCL->buffer[3].control = registerData;
-
- // Keep trying to run the program til it succeeds or we notice a reset or timeout condition.
- while( !pPCL->buffer[3].address ) {
-
- // Start the Rx PCL program at the given PCL.
- pLynxRegs->dmaChannel[kDMARegisterAccess].curPCLAddr =
- EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessDummyPCL + stackPtr]));
- SynchronizeIO();
-
- // Enable the DMA.
- pLynxRegs->dmaChannel[kDMARegisterAccess].ready =
- EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
- SynchronizeIO();
- pLynxRegs->dmaChannel[kDMARegisterAccess].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO();
-
- // Wait for DMA to stop (flag will never get set)
- status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, (UInt32 *)&pPCL->buffer[3].address, 0xFFFFFFFF );
- if( status )
- goto end; // Turn on read responses? Probably need a reset now anyway
- }
-
- end:
- // Suspend FWIM, wait 5 seconds for power to come back
- if( status )
- LynxFWIMWaitForPHYPower(pLynxFWIMData,false);
-
- DecrementAtomic( &pLynxFWIMData->phyRegAccessStack);
- return(status);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetRegisterBits
- //
- // Uses the above DMA routines to set some bits in a register field. The
- // register is read, and the new bits are or'd in and then the register
- // is written back.
- //
-
- static OSStatus LynxFWIMSetRegisterBits(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData )
- {
- UInt32 existingRegisterData;
- OSStatus status = noErr;
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData, registerAddress, &existingRegisterData);
-
- if( !status ) {
- existingRegisterData |= registerData;
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData, registerAddress, existingRegisterData );
- }
-
- return( status );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMClearRegisterBits
- //
- // Uses the above DMA routines to clear some bits in a register field. The
- // register is read, and the new bits are and'd with the complement of what
- // was already there and the result is is written back.
- //
-
- static OSStatus LynxFWIMClearRegisterBits(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 * registerAddress,
- UInt32 registerData )
- {
- UInt32 existingRegisterData;
- OSStatus status = noErr;
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData, registerAddress, &existingRegisterData);
-
- if( !status ) {
- existingRegisterData &= ~registerData;
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData, registerAddress, existingRegisterData );
- }
-
- return( status );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWaitAsyncTXFree
- //
- // Waits for the TX channel to finish what its doing.
- //
-
- static OSStatus LynxFWIMWaitAsyncTXFree(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 dmaChannel,
- UInt32 * waitFlag,
- UInt32 waitValue )
- {
- LynxRegistersPtr pLynxRegs;
- AbsoluteTime timeoutAbsolute, timeLeft;
- UInt32 patience;
- OSStatus status = noErr;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Wait for the following to tell us the transmit/register access DMA on this channel has
- // completed:
- //
- // If the DMA is stopped we are done.
- // If the transmitter is off we are done
- // If we have waited 50 ms and nothing has happend we are done.
- // If *waitFlag == waitValue we are done
- //
-
- // Start with a short delay in case its done already.
- // We need at least a short delay here cause the Link part will choke if
- // we access it quickly enough after it issues a target abort - or at least
- // as far as I can tell. -DCB
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (25 * durationMicrosecond));
-
- // Wait at most 50 milliseconds.
- patience = 50;
-
- while( patience && (*waitFlag != waitValue) )
- {
- // Check only rarely for bus reset or DMA stopping
- timeLeft = SubAbsoluteFromAbsolute (timeoutAbsolute, UpTime ()); // returns 0 if negative
- if (AbsoluteToDuration (timeLeft) == 0)
- {
- // We used to check for the transmitter becoming disabled here. We no longer do this because accessing
- // that register requires a DMA safe read which, well, brings us back here. Now we just wait for the
- // 50 millisecond timeout instead. Seems reasonable, as the bus would have been reset anyway at that
- // point.
- if( !patience || !(EndianSwap32Bit(pLynxRegs->dmaChannel[dmaChannel].control) & kLynxDMA_BSY) )
- {
- pLynxRegs->dmaChannel[dmaChannel].control = EndianSwapImm32Bit (0);
- SynchronizeIO ();
-
- *waitFlag = waitValue; // Tell whomevers waiting this puppy is a done as its gonna get
-
- if( !(EndianSwap32Bit(pLynxRegs->dmaChannel[dmaChannel].control) & kLynxDMA_BSY) ) {
- if( pLynxRegs->dmaChannel[dmaChannel].status & EndianSwapImm32Bit(kLynxMstErr))
- {
- pLynxRegs->dmaChannel[dmaChannel].status |= EndianSwapImm32Bit(kLynxMstErr);
- SynchronizeIO ();
- status = paramErr; // JKL *** better error?
- }
- else
- status = noErr; // DMA being stopped is not a error
- }
- else
- status = timeoutErr; // !!! Proper Error?
- break;
- }
- else
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
- patience--;
- }
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetLinkControl
- //
- // This proc sets the link control register and updates various link control
- // parameters.
- //
- // IMPORTANT! For consistency with other routines I changed the endianness of the
- // linkControl parameter. Now you swap it before calling this function.
- // DCB - 6/4/98
- //
-
- static OSStatus LynxFWIMSetLinkControl(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl)
- {
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- // Set asyncRxOverflowSetLinkControl in FWIM data.
- //zzz still have synchronization issues with async receive DMA
- pLynxFWIMData->asyncRxOverflowSetLinkControl =
- EndianSwap32Bit (linkControl | kLynxBUSY_CNTRL);
-
- // Set linkControl register.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->linkControl,
- (UInt32 ) linkControl );
- SynchronizeIO ();
-
- return status;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetLinkControlBits
- //
- // Uses the above DMA routines to set some bits in a register field. The
- // register is read, and the new bits are or'd in and then the register
- // is written back.
- //
-
- static OSStatus LynxFWIMSetLinkControlBits (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl)
- {
- UInt32 existingRegisterData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData, (UInt32 *) &pLynxRegs->linkControl, &existingRegisterData);
-
- if( !status ) {
- existingRegisterData |= linkControl;
- status = LynxFWIMSetLinkControl( pLynxFWIMData, existingRegisterData );
- }
-
- return( status );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMClearLinkControlBits
- //
- // Uses the above DMA routines to clear some bits in a register field. The
- // register is read, and the new bits are and'd with the complement of what
- // was already there and the result is is written back.
- //
-
- static OSStatus LynxFWIMClearLinkControlBits (
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 linkControl)
- {
- UInt32 existingRegisterData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData, (UInt32 *) &pLynxRegs->linkControl, &existingRegisterData);
-
- if( !status ) {
- existingRegisterData &= ~linkControl;
- status = LynxFWIMSetLinkControl( pLynxFWIMData, existingRegisterData );
- }
-
- return( status );
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetAsyncRxComparatorMask1
- //
- // This proc sets the async receive mask1 comparator and updates some
- // parameters.
- //
-
- static void LynxFWIMSetAsyncRxComparatorMask1(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 mask1)
- {
- LynxRegistersPtr pLynxRegs;
-
- // Set asyncRxOverflowSetPCLComparator in FWIM data.
- //zzz still have synchronization issues with async receive DMA
- pLynxFWIMData->asyncRxOverflowSetPCLComparator =
- EndianSwap32Bit (mask1 & ~kLynxEN_CH_COMPARE);
-
- // Set comparator register.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
- (UInt32)EndianSwap32Bit (mask1));
- SynchronizeIO ();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWriteATF
- //
- // Common code for writing an ATF packet
- //
-
- static OSStatus LynxFWIMWriteATF(
- LynxFWIMDataPtr pLynxFWIMData,
- UInt32 transmitType,
- UInt32 speed,
- UInt32 baseCount, // count [1-4] of quads below:
- UInt32 data1,
- UInt32 data2,
- UInt32 data3,
- UInt32 data4,
- UInt32 extCount, // count in BYTES of data below:
- UInt32 *extData)
- {
- LynxRegistersPtr pLynxRegs;
- IOPreparationTable ioPreparationTable;
- UInt32 dataBuffer[4];
- UInt32 pclControl;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteATF");
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Set up data PCL.
- dataBuffer[0] = data1;
- dataBuffer[1] = data2;
- dataBuffer[2] = data3;
- dataBuffer[3] = data4;
- pclControl = (transmitType << kLynxDMA_CMDPhase) | kLynxDMA_WAIT_FOR_STATUS;
- if (speed == kFWSpeed200MBit)
- pclControl |= kLynxDMA200mbps << kLynxDMA_xmit_spd_codePhase;
- else if (speed == kFWSpeed400MBit)
- pclControl |= kLynxDMA400mbps << kLynxDMA_xmit_spd_codePhase;
- LynxFWIMBuildAsyncTxPCL (pLynxFWIMData,
- &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]),
- &ioPreparationTable,
- pclControl,
- (Ptr) &dataBuffer[0],
- baseCount * sizeof (UInt32),
- (Ptr) extData,
- extCount);
-
- // Add data PCL to async transmit program and start.
- LynxFWIMAddAsyncTxPCL (&(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
-
- #if 0
- // This way is bad. We hammer the link control register via PCI.
- // That causes FIFO underflows on big packets.
- // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
- //
- // If this gets turned back on, use safe register access for the linkControl...
- while ((EndianSwap32Bit(pLynxRegs->linkControl) & kLynxTX_ASYNC_EN) &&
- !(pLynxFWIMData->asyncTxDoneFlag));
- #endif
-
- // This still isn't great. We should just return, and then handle completion or
- // failure later, when an interrupt or timer goes off.
-
- // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
- // Check TX disable only once per millisecond. Try this for at most 50 milliseconds.
- // !!! What the heck do we do if we timeout?
-
-
- // Wait til pLynxFWIMData->asyncTxDoneFlag == 0xFFFFFFFF
- status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kAsyncTransmitDMA, (UInt32 *)&pLynxFWIMData->asyncTxDoneFlag, 0xFFFFFFFF );
-
- // Clean up transmission.
- CheckpointIO (ioPreparationTable.preparationID, kNilOptions);
- pLynxFWIMData->pNextAsyncTxPCL =
- pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL].pNextPCL;
-
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMBuildAsyncTxPCL
- //
- // This proc builds an asynchronous transmit PCL from the given parameters.
- // buffer1 is assumed to be small. It is usually a packet header. buffer2 is
- // assumed to be larger and typically is a packet payload.
- //
-
- static OSStatus LynxFWIMBuildAsyncTxPCL(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- IOPreparationTable *ioPreparationTable,
- UInt32 pclControl,
- Ptr buffer1,
- UInt32 size1,
- Ptr buffer2,
- UInt32 size2)
- {
- PhysicalAddress physicalMapping[kMaxBufPage];
- UInt32 pageSize,
- pageShift;
- UInt32 numPages;
- Ptr preparedBuffer;
- UInt32 seg1Size,
- seg2Size,
- seg3Size;
- UInt32 seg2AlignSize;
- UInt32 transferSize;
- UInt32 pclBufferNum;
- UInt32 pageNum;
- OSStatus status = noErr;
-
- // Get some FWIM parameters.
- pageSize = pLynxFWIMData->pageSize;
- pageShift = pLynxFWIMData->pageShift;
- preparedBuffer = pLynxFWIMData->asyncXmitBuf;
-
- // Do initial PCL set up.
- pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pPCL->status = EndianSwapImm32Bit (0);
- pPCL->remaining = EndianSwapImm32Bit (0);
- pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
-
- // Set up initial segment sizes, PCL buffer number, and ioPreparationTable.
- seg1Size = size1;
- seg2Size = size2;
- seg3Size = 0;
- pclBufferNum = 0;
- ioPreparationTable->preparationID = kInvalidID;
-
- // Add buffer1 to our prepared buffer.
- if (size1 > 0)
- {
- BlockCopy (buffer1, preparedBuffer, size1);
- preparedBuffer += size1;
- }
-
- // Add data from buffer2 to our prepared buffer to 32 byte align second segment.
- if ((((UInt32) buffer2) & 31) > 0)
- seg2AlignSize = 32 - (((UInt32) buffer2) & 31);
- else
- seg2AlignSize = 0;
- if (seg2AlignSize > size2)
- seg2AlignSize = size2;
- if (seg2AlignSize > 0)
- {
- BlockCopy (buffer2, preparedBuffer, seg2AlignSize);
- preparedBuffer += seg2AlignSize;
- seg1Size += seg2AlignSize;
- buffer2 += seg2AlignSize;
- seg2Size -= seg2AlignSize;
- }
-
- // Add prepared buffer to PCL.
- pPCL->buffer[pclBufferNum].control = EndianSwap32Bit (pclControl | seg1Size);
- pPCL->buffer[pclBufferNum].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncXmitBufPhys);
- pclBufferNum++;
-
- // Add rest of buffer2 to PCL.
- if (seg2Size > 0)
- {
- // Set up IO preparation table.
- numPages = ((((UInt32) buffer2) + seg2Size - 1) >> pageShift) -
- (((UInt32) buffer2) >> pageShift) + 1;
- ioPreparationTable->options = kIOLogicalRanges | kIOIsOutput;
- ioPreparationTable->addressSpace = kCurrentAddressSpaceID;
- ioPreparationTable->granularity = 0;
- ioPreparationTable->firstPrepared = 0;
- ioPreparationTable->mappingEntryCount = numPages;
- ioPreparationTable->logicalMapping = 0;
- ioPreparationTable->physicalMapping = physicalMapping;
- ioPreparationTable->rangeInfo.range.base = buffer2;
- ioPreparationTable->rangeInfo.range.length = seg2Size;
-
- // Prepare.
- status = PrepareMemoryForIO (ioPreparationTable);
- /*zzz*/
- if (status != noErr)
- {
- sprintf (debugStr, "PrepareMemoryForIO error %ld", status);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- /*zzz*/
-
- // Add pages to PCL.
- if (status == noErr)
- {
- // Compute first page transfer size.
- if (numPages > 1)
- transferSize = pageSize - (((UInt32) buffer2) & (pageSize - 1));
- else
- transferSize = seg2Size;
-
- // Add first page to PCL.
- pPCL->buffer[pclBufferNum].control =
- EndianSwap32Bit (pclControl | transferSize);
- pPCL->buffer[pclBufferNum].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[0]);
- pclBufferNum++;
-
- // Add rest of pages except last one to PCL.
- for (pageNum = 1; pageNum < (numPages - 1); pageNum++)
- {
- // Add page to PCL.
- pPCL->buffer[pclBufferNum].control =
- EndianSwap32Bit (pclControl | pageSize);
- pPCL->buffer[pclBufferNum].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[pageNum]);
- pclBufferNum++;
- }
-
- // Add last page to PCL.
- if (numPages > 1)
- {
- transferSize = (((UInt32) buffer2) + seg2Size) & (pageSize - 1);
- pPCL->buffer[pclBufferNum].control =
- EndianSwap32Bit (pclControl | transferSize);
- pPCL->buffer[pclBufferNum].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[numPages - 1]);
- pclBufferNum++;
- }
- }
- }
-
- // Add zero padding to PCL.
- if (status == noErr)
- {
- // Compute amount of zero padding.
- if ((size2 & 3) > 0)
- {
- seg3Size = 4 - (size2 & 3);
-
- // Use prepared buffer for zeros.
- ((UInt32 *) pLynxFWIMData->asyncXmitBuf)[128] = 0;
-
- // Add to PCL.
- pPCL->buffer[pclBufferNum].control =
- EndianSwap32Bit (pclControl | seg3Size);
- pPCL->buffer[pclBufferNum].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) (pLynxFWIMData->asyncXmitBufPhys) + 512);
- pclBufferNum++;
- }
- }
-
- // Set last buffer.
- if (status == noErr)
- pPCL->buffer[pclBufferNum - 1].control |= EndianSwapImm32Bit (kLynxDMA_LAST_BUF);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMRead
- //
- // This proc performs a read transaction on the FireWire bus.
- // We write the read command, the completion is handled elsewhere
- // when we get an interrupt for the receipt of the response.
- //zzz what if timer goes off before request goes out???
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus LynxFWIMRead(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 data1, data2, data3, data4;
- UInt32 sourceID;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMRead");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // already has bit alignment we'll need later...
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- sourceID = EndianSwap32Bit( sourceID );
- }
-
- // Check if generation is up to date.
- if( !status ) {
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // If we wanted to be really clever, we could program up a spare DMA channel to
- // match the sourceID, tCode, and tLabel, causing the response to be DMAed
- // directly into the desired location, skipping an in-memory copy.
-
- // Warning - it is ESSENTIAL that reads which fail trigger the timeout handler.
- // FSL can't handle reads that just "vanish". But, rather than go thru the handler,
- // maybe we can return a failure below.
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMRead - setting timer for failure");
- // Set a timeout timer.
- if (status == noErr)
- {
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMReadRequestTimeoutHandler,
- pFWIMAsynchCommandParams,
- &(pLynxFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pLynxFWIMData->requestTimeoutTimerSet = true;
- }
-
- // sometimes FSL tries to read from the local node, which won't work.
- // rather than bothering the DMA engine, just let the timeout timer
- // return the error. (return now - NYI)
-
- // Write read request to ATF.
- if (status == noErr)
- {
- // Need to send at correct speed (WriteAFT always sends at 100)
- pLynxFWIMData->transactionLabel =
- (pLynxFWIMData->transactionLabel + 1) & 0x3F;
-
- // Header quad common to quadlet and block:
- data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
- data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
- data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
-
- // Packet address same for both:
- data2 = sourceID;
- data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- if (pFWIMAsynchCommandParams->length == 4)
- { // Quadlet request.
-
- pLynxFWIMData->tCode = kFWTCodeReadQuadlet;
- data1 |= (kFWTCodeReadQuadlet << kFWPacketTCodePhase);
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 3, data1, data2, data3, 0, 0, 0);
- }
- else
- { // Block request.
-
- pLynxFWIMData->tCode = kFWTCodeReadBlock;
- data1 |= (kFWTCodeReadBlock << kFWPacketTCodePhase);
-
- data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
- }
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReadResponse
- //
- // This proc sends a read response packet.
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus LynxFWIMReadResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 data1, data2, data4;
- UInt32 sourceID;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // already has bit alignment we'll need later...
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
- }
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Write read response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
- data1 |= transactionLabel << kFWAsynchTLabelPhase;
- data1 |= kFWAsynchNew << kFWAsynchRtPhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = sourceID;
- data2 |= responseCode << kFWAsynchRCodePhase;
-
- // packet payload goes in quad 4
- data4 = (*((UInt32 *) pFWIMAsynchResponseCommandParams->buffer));
-
- if (pFWIMAsynchResponseCommandParams->length == 4)
- { // Quadlet request.
-
- data1 |= kFWTCodeReadQuadletResponse << kFWPacketTCodePhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, 0, 0);
- }
- else
- { // Block request.
-
- data1 |= kFWTCodeReadBlockResponse << kFWPacketTCodePhase;
-
- data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
- }
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMResponseCommand = nil;
- FWIMCommandIsComplete(pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWrite
- //
- // This proc performs a write transaction on the FireWire bus.
- //zzz what if timer goes off before request goes out??? A: Execute this proc
- //zzz at secondary interrupt level
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus LynxFWIMWriteTimer(
- void *p1,
- void *p2)
- {
- UInt32 commandAcceptance;
- OSStatus status = noErr;
-
- status = LynxFWIMWrite ((FWIMAsynchCommandParamsPtr) p1, &commandAcceptance);
- return (status);
- }
-
- static OSStatus LynxFWIMWrite(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
- UInt32 data1, data2, data3, data4;
- UInt32 sourceID;
-
- static UInt32 debug = 0;
-
- // sprintf (debugStr, "FWIM Write %ld bytes", (long) pFWIMAsynchCommandParams->length);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Timer is off.
- pLynxFWIMData->requestTimeoutTimerSet = false;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- //zzz need to set a timeout timer in case we get a ack_pending
-
- // already has bit alignment we'll need later...
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- sourceID = EndianSwap32Bit( sourceID );
-
- // Write write request to ATF.
- if (status == noErr)
- {
- if (pFWIMAsynchCommandParams->length == 4)
- { // Quadlet request.
- // Write packet control header.
- data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
-
- pLynxFWIMData->transactionLabel =
- (pLynxFWIMData->transactionLabel + 1) & 0x3F;
- pLynxFWIMData->tCode = kFWTCodeWriteQuadlet;
- data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
- data1 |= kFWAsynchNew << kFWAsynchRtPhase;
- data1 |= kFWTCodeWriteQuadlet << kFWPacketTCodePhase;
-
- // Write packet address.
- data2 = sourceID;
- data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // Write packet payload.
- data4 = (*((UInt32 *) pFWIMAsynchCommandParams->buffer));
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
- }
- else
- { // Block request.
- // Write packet control header.
- data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
-
- pLynxFWIMData->transactionLabel =
- (pLynxFWIMData->transactionLabel + 1) & 0x3F;
- pLynxFWIMData->tCode = kFWTCodeWriteBlock;
- data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
- data1 |= kFWAsynchNew << kFWAsynchRtPhase;
- data1 |= kFWTCodeWriteBlock << kFWPacketTCodePhase;
-
- // Write packet address.
- data2 = sourceID;
- data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // Write request length.
- data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
- pFWIMAsynchCommandParams->length,
- (UInt32 *) pFWIMAsynchCommandParams->buffer);
- }
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
- }
- else
- {
- // We no longer take TxRdy interrupt, instead, the status should already be waiting for us.
- //zzz We probably should take an interrupt. Other transmit stuff (like isoch) could
- //zzz be blocking this transmission for relatively long periods of time.
- LynxFWIMAckSecondaryInterruptHandler
- (pLynxFWIMData, &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWriteResponse
- //
- // This proc sends a write response packet.
- //zzz should be set up to get acknowledgement
- //
- //
-
- static OSStatus LynxFWIMWriteResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 data1, data2;
- UInt32 sourceID;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // already has bit alignment we'll need later...
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
- }
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Write write response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
- data1 |= kFWTCodeWriteResponse << kFWPacketTCodePhase;
- data1 |= transactionLabel << kFWAsynchTLabelPhase;
- data1 |= kFWAsynchNew << kFWAsynchRtPhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = sourceID;
- data2 |= responseCode << kFWAsynchRCodePhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 3, data1, data2, 0, 0, 0, 0);
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMResponseCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMLock
- //
- // This proc performs a lock transaction on the FireWire bus.
- //zzz what if timer goes off before request goes out??? A: Execute this proc
- //zzz at secondary interrupt level
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus LynxFWIMLock(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 data1, data2, data3, data4, sourceID;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMLock");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Set a timeout timer.
- if (status == noErr)
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (),
- DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
- status = SetInterruptTimer
- (&timeoutAbsolute, LynxFWIMLockRequestTimeoutHandler,
- pFWIMAsynchCommandParams,
- &(pLynxFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pLynxFWIMData->requestTimeoutTimerSet = true;
- }
-
- // send lock request.
- if (status == noErr)
- {
- pLynxFWIMData->transactionLabel =
- (pLynxFWIMData->transactionLabel + 1) & 0x3F;
- pLynxFWIMData->tCode = kFWTCodeLock;
-
- // Prepare packet control header for block transaction.
- data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
- data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
- data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
- data1 |= (kFWTCodeLock << kFWPacketTCodePhase);
-
- // our ID and the target address.
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- if( !status ) {
- sourceID = EndianSwap32Bit( sourceID );
- data2 = sourceID | (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // request length and extended tCode.
- data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
- data4 |=
- (pFWIMAsynchCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
- kFWAsynchExtendedTCodePhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
- pFWIMAsynchCommandParams->length,
- (UInt32 *) pFWIMAsynchCommandParams->buffer);
- }
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMLockResponse
- //
- // This proc sends a lock response packet.
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus LynxFWIMLockResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- UInt32 data1, data2, data4;
- UInt32 sourceID;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Get pointer to link registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- if( !status ) {
- // already has bit alignment we'll need later...
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->busNumberNodeNumber,
- (UInt32 *) &sourceID );
-
- sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
- }
-
- if( !status ) {
- // Check if generation is up to date.
- if ((!(pLynxFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
- }
-
- // Write lock response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
- data1 |= transactionLabel << kFWAsynchTLabelPhase;
- data1 |= kFWAsynchNew << kFWAsynchRtPhase;
- data1 |= kFWTCodeLockResponse << kFWPacketTCodePhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = sourceID;
- data2 |= responseCode << kFWAsynchRCodePhase;
-
- data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
- data4 |=
- (pFWIMAsynchResponseCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
- kFWAsynchExtendedTCodePhase;
-
- LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pLynxFWIMData->pPendingFWIMResponseCommand = nil;
- FWIMCommandIsComplete(pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMIsCompilableDCLProgram
- //
- // This routine determines if the given DCL program is compilable.
- //zzz a table and range check may be faster.
- //zzz should do better checking.
- //zzz maybe we should make this determination in a first pass compilation.
- //
-
- static Boolean LynxFWIMIsCompilableDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCommandPtr pDCLCommand;
- Boolean isCompilable = true;
- UInt32 opcode;
- OSStatus status = noErr;
-
- // Get first DCL in program.
- status = FWGetDCLProgramStart (dclProgramID, &pDCLCommand);
- if (status != noErr)
- isCompilable = false;
-
- // Check each DCL in program.
- while ((isCompilable) && (pDCLCommand != nil))
- {
- opcode = pDCLCommand->opcode;
- opcode &= ~kFWDCLOpDynamicFlag; // We can compile dynamic opcodes.
- switch (opcode)
- {
- case kDCLReceivePacketStartOp :
- break;
-
- case kDCLReceivePacketOp :
- break;
-
- case kDCLSendPacketStartOp :
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- break;
-
- case kDCLSendPacketOp :
- break;
-
- case kDCLCallProcOp :
- break;
-
- case kDCLJumpOp :
- break;
-
- case kDCLLabelOp :
- break;
-
- case kDCLSetTagSyncBitsOp :
- break;
-
- case kDCLUpdateDCLListOp :
- break;
-
- case kDCLTimeStampOp :
- break;
-
- default :
- isCompilable = false;
- break;
- }
-
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- return (isCompilable);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPrepareDCLProgramMemory
- //
- // This routine prepares all buffers used within a DCL program for physical
- // I/O, and determines the physical addresses. dclList is the entire program.
- //
-
- static OSStatus LynxFWIMPrepareDCLProgramMemory(
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData,
- DCLCommandPtr dclList,
- UInt32 dclListLength)
- {
- DCLCommandPtr pDCL;
- DCLTransferPacketPtr pDCLTransferPacket;
- IOPreparationTable *ioPrep;
- PhysicalAddress *physAddrs; // should be PhysicalMappingTablePtr
- AddressRangeTablePtr rangeTable;
- UInt32 pageSize, pageShift, pageMask, tmp;
- UInt32 pageCount, bufferCount;
- AbsoluteTime timeNow;
- OSStatus status = noErr;
-
- ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
- pageSize = GetLogicalPageSize ();
- pageShift = 0;
- for (tmp = pageSize; tmp = tmp >> 1; pageShift++); // Sorry...
- pageMask = ~(pageSize - 1);
-
- // This is gross too. Make sure we don't use stale data in lookups.
- timeNow = UpTime ();
- pLynxDCLCompilerEngineData->engineGeneration = AbsoluteToDuration (timeNow);
-
- // We will need to allocate a page table. We don't know how big it needs
- // to be, but we can wait until just before we PrepareMemoryForIO to do
- // the allocation (by then we'll know)
-
- // We need to allocate a range/length table. We fill that in before we
- // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
- // it all at once. We need one entry for each buffer in the program.
- // That's why we take a parameter indicating the program length.
- // Note if we ever allow scatter/gather buffers in a DCL program, this
- // will have to change.
-
- // We assumed (in LynxFWIMCompileDCLProgram) that each DCL contained a buffer.
- // Some of them are branches, etc, so an optimization would be to count more
- // precisely and save a little memory.
-
- // Allocate space for rangeTable
- if (status == noErr)
- {
- rangeTable = (AddressRangeTablePtr)
- PoolAllocateResident (dclListLength * sizeof (AddressRange), false);
- if (!rangeTable) status = memFullErr;
- ioPrep->rangeInfo.multipleRanges.entryCount = 0;
- // move this below, use local copy
- ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
- }
-
- // Gather information about buffers/pointers
- if (status == noErr)
- {
- pDCL = dclList;
- bufferCount = 0; // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
- pageCount = 0; // count page table size we will need to allocate
-
- while (pDCL != nil)
- {
- switch (pDCL->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLReceivePacketStartOp :
- case kDCLReceivePacketOp :
- case kDCLSendPacketStartOp :
- case kDCLSendPacketWithHeaderStartOp :
- case kDCLSendPacketOp :
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
- rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
- rangeTable[bufferCount].length = pDCLTransferPacket->size;
- bufferCount++;
-
- // buffer + size - 1 is addr of last byte in buffer.
- // shift that right by pageShift to get page index of end.
- // subtract first page index and add one to get total page count.
-
- pageCount += // (last page - first page) + 1
- ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
- (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
- break;
-
- default : //No buffer or pointer - nothing to do
- break;
- }
-
- pDCL = pDCL->pNextDCLCommand;
- }
- }
-
- // Allocate space for page table
- if (status == noErr)
- {
- physAddrs = PoolAllocateResident (pageCount * sizeof (PhysicalAddress), false);
- if (!physAddrs)
- {
- status = memFullErr;
- PoolDeallocate ((Ptr) rangeTable);
- }
- pLynxDCLCompilerEngineData->physAddrs = physAddrs;
- }
-
- // Prepare memory for I/O
- if (status == noErr)
- {
- ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
- kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = pageCount; // we counted exactly
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
-
- // CheckpointIO is in _LynxFWIMReleaseIsochPort
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- ioPrep->mappingEntryCount = -1; // prevents CheckpointIO, kind of a hack
- PoolDeallocate ((Ptr) rangeTable);
- PoolDeallocate ((Ptr) physAddrs);
-
- sprintf (debugStr, "DCL data PrepMemIO status %ld page count %ld",
- (long) status,
- (long) pageCount);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDMapBufferToPhysical
- //
- // This routine looks up physical addresses for buffers/pointers.
- // Fills in the passed page table, returns page count (0 if not found)
-
- static UInt32 LynxFWIMDataMapToPhysical (
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData,
- Ptr pBuffer,
- UInt32 size,
- PhysicalMappingTablePtr returnTable)
- {
- UInt32 pageCount = 0, lookCount = 0;
- static UInt32 rangeLook = 0, pageLook = 0;
- static UInt32 pageSize = 0, pageShift = 0;
- static UInt32 cacheEngineGeneration = 0;
- IOPreparationTable *ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
- AddressRangeTablePtr try;
- if (!pageSize)
- {
- UInt32 tmp;
- pageSize = GetLogicalPageSize ();
- for (tmp = pageSize; tmp = tmp >> 1; pageShift++); // Sorry...
- }
-
- // Look up phys addrs in our prepared table
- // Return in provided page table
-
- // Start lookup from last known point, if we build in order, lookup is fast
- // Strictly speaking, rangeLook and pageLook should be static to the
- // engine data, not the whole FWIM, but I don't think we can compile more
- // than one DCL program at a time anyway.
- //
- // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
- // because they may be off the end or otherwise inaccurate.
- //
- // I'm not sure this (optimization) works - it still seems sluggish.
-
- if (cacheEngineGeneration != pLynxDCLCompilerEngineData->engineGeneration)
- {
- cacheEngineGeneration = pLynxDCLCompilerEngineData->engineGeneration;
- rangeLook = 0;
- pageLook = 0;
- }
-
- // Repeat until we find it or run out of places to look
-
- while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && (!pageCount))
- {
- try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
-
- // pageCount is number of physAddr entries used by this range
- // either copy them (found) or skip over them (not found)
-
- pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
- ((UInt32) try->base >> pageShift);
-
- // require exact match
- if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
- {
- // Found pages we want. Copy page table.
- BlockCopy (&ioPrep->physicalMapping[pageLook],
- returnTable,
- pageCount * sizeof (PhysicalAddress));
- pageLook += pageCount;
- }
- else
- {
- // These aren't the pages we're looking for. Skip forward.
- pageLook += pageCount;
- pageCount = 0;
- }
-
- lookCount++;
- rangeLook++;
- if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
- {
- rangeLook = 0;
- pageLook = 0;
- }
- }
-
- if (!pageCount)
- FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
-
- return pageCount;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMCompileDCLProgram
- //
- // This routine compiles the given DCL program into a PCL program.
- //zzz rename this
- //zzz need to convert data endianess (really? I think Lynx DMA does that)
- //zzz need to set proper speed.
- //
-
- static OSStatus LynxFWIMCompileDCLProgram(
- LynxFWIMDataPtr pLynxFWIMData,
- DCLProgramID dclProgramID,
- UInt32 pclChannelNum,
- UInt32 channelNum,
- UInt32 speed)
- {
- LynxPCLBuildStatePtr pLynxPCLBuildState = nil;
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData = nil;
- DCLCommandPtr pDCLCommand,
- dclList;
- DCLLabel waitLoopDCLLabel,
- transmitDCLLabel;
- DCLCommand waitLoopDCLCommand;
- LynxPCLPtr pStartPCL;
- UInt32 startEvent,
- startEventState,
- startEventStateMask;
- UInt32 dclListLength;
- OSStatus status = noErr;
-
- // Create DCL engine data record.
- pLynxDCLCompilerEngineData = (LynxDCLCompilerEngineDataPtr)
- PoolAllocateResident (sizeof (LynxDCLCompilerEngineData), true);
- if (pLynxDCLCompilerEngineData == nil)
- status = memFullErr;
-
- // Initialize interrupt queue.
- if (status == noErr)
- {
- pLynxFWIMData->pDCLInterruptTail[pclChannelNum] = nil;
- pLynxFWIMData->pDCLLastInterrupt[pclChannelNum] = nil;
- }
-
- // Set compiler notification proc.
- if (status == noErr)
- {
- status = FWSetDCLProgramCompilerNotificationProc
- (dclProgramID, LynxFWIMDCLCompilerNotification);
- }
-
- // Get DCL list from program.
- //zzz should check for error.
- if (status == noErr)
- status = FWGetDCLProgramStart (dclProgramID, &dclList);
-
- // Clear compiler data in all DCLs, and count them.
- if (status == noErr)
- {
- pDCLCommand = dclList;
- dclListLength = 0;
- while (pDCLCommand != nil)
- {
- pDCLCommand->compilerData = nil;
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- dclListLength++;
- }
- }
-
- // The plan is to, before compiling, scan the program to locate all data
- // buffers. Then we'll prepare VM mappings for them all at once. Then
- // during compilation we can look up the logical->physical mappings.
- //
- // A complication is that we may receive notification that a running
- // program has had its buffers changed. We get a list of changes. In
- // that case we need to prepare the new buffers for DMA and change the
- // pointers in the PCLs, possibly expanding PCLs if there are more
- // page crossings than before. (or maybe not)
- //
- // When we update buffers, some may be unchanged, so we can't clear the
- // original PrepareMemoryForIO. Buffers can be updated repeatedly, and
- // we could pile up unlimited ioPrep structures. So we use a brute-force
- // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
- // Then we can free (CheckpointIO) the original one, and all live buffers
- // are still covered. (There is room for optimizations in that process.)
- //
- // The first time we prepare memory, we have the luxury that the program
- // is not running. When we do updates, the program *is* running. But maybe
- // we can use the same code both times, somehow.
-
- if (status == noErr)
- status = LynxFWIMPrepareDCLProgramMemory (pLynxDCLCompilerEngineData,
- dclList,
- dclListLength);
-
- // Start our PCL program.
- if (status == noErr)
- {
- status = LynxFWIMPCLStart (pLynxFWIMData, &pLynxPCLBuildState, &pStartPCL);
-
- if (status == noErr)
- {
- pLynxPCLBuildState->pLynxDCLCompilerEngineData = pLynxDCLCompilerEngineData;
- pLynxPCLBuildState->pclChannelNum = pclChannelNum;
- pLynxPCLBuildState->isochChannelNum = channelNum;
-
- // When we called PCLStart we allocated the first pool of PCLs (physical memory)
- // make a note of where the isoch packet header is, we'll use that for this program
-
- // This is the header's true location and contents.
- pLynxDCLCompilerEngineData->isochPacketHeaderPtr =
- &(pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeader);
- *(pLynxDCLCompilerEngineData->isochPacketHeaderPtr) =
- (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
- (channelNum << kFWIsochChanNumPhase);
-
- // make note of the physical address
- pLynxDCLCompilerEngineData->isochPacketHeaderPhys =
- pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeaderPhys;
-
- #ifdef LynxVMDebug
- if (((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPtr)) !=
- ((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPhys)))
- {
- sprintf (debugStr, "Isoch header PTR (A) logical %08lx != physical %08lx",
- (long) pLynxDCLCompilerEngineData->isochPacketHeaderPtr,
- (long) pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
- }
-
- // Check if there's a start event for the cycle count.
- if (status == noErr)
- {
- status = FWGetDCLProgramStartEvent
- (dclProgramID, &startEvent, &startEventState, &startEventStateMask);
- }
- if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
- {//zzz need to deal with mask including upper 16 bits
- // Create some DCLs to wait for cycle event.
- waitLoopDCLLabel.pNextDCLCommand = &waitLoopDCLCommand;
- waitLoopDCLLabel.compilerData = nil;
- waitLoopDCLLabel.opcode = kDCLLabelOp;
-
- waitLoopDCLCommand.pNextDCLCommand = (DCLCommandPtr) &transmitDCLLabel;
- waitLoopDCLCommand.compilerData = nil;
- waitLoopDCLCommand.opcode = kDCLInvalidOp;
-
- transmitDCLLabel.pNextDCLCommand = dclList;
- transmitDCLLabel.compilerData = nil;
- transmitDCLLabel.opcode = kDCLLabelOp;
-
- // Add wait loop label.
- status =
- LynxFWIMAddLabelDCL (pLynxPCLBuildState, (DCLCommandPtr) &waitLoopDCLLabel);
-
- // Add a wait for cycle count commands.
- // We must set up to start filling the cycle before the cycle we want the packet
- // to go out on.
- //zzz setting a compare for startEventState - (1 << 12) will only work right
- //zzz when bit 12 is set in the mask.
- if (status == noErr)
- {
- //This address is already physical, no translation needed
- status =
- LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
- (Ptr) &(pLynxFWIMData->pLynxRegisters->cycleTimer));
- }
- if (status == noErr)
- {
- status = LynxFWIMPCLCompareTemp16WithMask (pLynxPCLBuildState,
- startEventState - (1 << 12),
- startEventStateMask);
- }
- if (status == noErr)
- status = LynxFWIMPCLBranchIfEqual (pLynxPCLBuildState, &transmitDCLLabel);
- if (status == noErr)
- status = LynxFWIMPCLJump (pLynxPCLBuildState, &waitLoopDCLLabel, nil);
-
- // Add transmit label.
- if (status == noErr)
- {
- status = LynxFWIMAddLabelDCL (pLynxPCLBuildState,
- (DCLCommandPtr) &transmitDCLLabel);
-
- // Set ready register to 1 after we exit the wait loop.
- // We'll stop transmitting if we find ready has been zeroed.
-
- status = LynxFWIMPCLStore1 (pLynxPCLBuildState,
- (Ptr) &(pLynxFWIMData->pLynxRegisters->dmaChannel[pclChannelNum].ready));
- }
- }
- else
- {
- // set ready to 1 if start event is kFWDCLImmediateEvent
- status = LynxFWIMPCLStore1 (pLynxPCLBuildState,
- (Ptr) &(pLynxFWIMData->pLynxRegisters->dmaChannel[pclChannelNum].ready));
- }
-
- // Process all DCLs.
- pDCLCommand = dclList;
- while ((pDCLCommand != nil) && (status == noErr))
- {
- status = LynxFWIMAddDCL (pLynxPCLBuildState, pDCLCommand);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- // Fill in DCL engine data record.
- if (status == noErr)
- {
- pLynxDCLCompilerEngineData->pStartPCL = pStartPCL;
- pLynxDCLCompilerEngineData->pLynxPCLPoolDataList =
- pLynxPCLBuildState->pLynxPCLPoolDataList;
- pLynxDCLCompilerEngineData->pLynxFWIMData = pLynxFWIMData;
- }
-
- // Save engine data.
- if (status == noErr)
- {
- status = FWSetDCLProgramEngineData (dclProgramID,
- (UInt32) pLynxDCLCompilerEngineData);
- }
-
- // Clean up on error.
- if (status != noErr)
- {
- // Deallocate PCL pools.
- if (pLynxPCLBuildState != nil)
- if (pLynxPCLBuildState->pLynxPCLPoolDataList != nil)
- LynxFWIMDeallocatePCLPools (pLynxPCLBuildState->pLynxPCLPoolDataList);
-
- // Deallocate engine data.
- if (pLynxDCLCompilerEngineData != nil)
- PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
- }
-
- // Clean up.
- if (pLynxPCLBuildState != nil)
- PoolDeallocate ((Ptr) pLynxPCLBuildState);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddDCL
- //
- // This proc adds the given DCL.
- //
-
- static OSStatus LynxFWIMAddDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- UInt32 opcode;
- OSStatus status = noErr;
-
- // Dispatch off of opcode.
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
- switch (opcode)
- {
- case kDCLReceivePacketStartOp :
- if (status == noErr)
- status = LynxFWIMAddReceivePacketStartDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLReceivePacketOp :
- if (status == noErr)
- status = LynxFWIMAddReceivePacketDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketStartOp :
- if (status == noErr)
- status = LynxFWIMAddSendPacketStartDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- if (status == noErr)
- {
- status = LynxFWIMAddSendPacketWithHeaderStartDCL
- (pLynxPCLBuildState, pDCLCommand);
- }
- break;
-
- case kDCLSendPacketOp :
- status = LynxFWIMAddSendPacketDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLCallProcOp :
- status = LynxFWIMAddCallProcDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLJumpOp :
- status = LynxFWIMAddJumpDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLLabelOp :
- status = LynxFWIMAddLabelDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLSetTagSyncBitsOp :
- status = LynxFWIMAddSetTagSyncBitsDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLUpdateDCLListOp :
- status = LynxFWIMUpdateDCLListDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- case kDCLTimeStampOp :
- status = LynxFWIMTimeStampDCL (pLynxPCLBuildState, pDCLCommand);
- break;
-
- default : //zzz what can we do?
- break;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddReceivePacketStartDCL
- //
- // This proc adds a receive packet start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus LynxFWIMAddReceivePacketStartDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
-
- // Start new receive PCL.
- status = LynxFWIMPCLNewIsochReceive
- (pLynxPCLBuildState,
- (LynxPCLPtr *) &(pDCLTransferPacket->compilerData),
- (UInt32) pDCLTransferPacket,
- kLynxDMA100mbps);
-
- // Add payload buffer.
- if (status == noErr)
- {
- status = LynxFWIMPCLAddTransferBuffer
- (pLynxPCLBuildState,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- (Ptr *) &(pDCLTransferPacket->compilerData),
- kLynxLogicalBuffer);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddReceivePacketDCL
- //
- // This proc adds a receive packet DCL.
- //
-
- static OSStatus LynxFWIMAddReceivePacketDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
-
- // Add payload buffer.
- if (status == noErr)
- {
- status = LynxFWIMPCLAddTransferBuffer
- (pLynxPCLBuildState,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- (Ptr *) &(pDCLTransferPacket->compilerData),
- kLynxLogicalBuffer);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddSendPacketStartDCL
- //
- // This proc adds a send packet start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus LynxFWIMAddSendPacketStartDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket,
- pDCLTransferPacketStart;
- UInt32 packetSize;
- UInt32 packetHeader,
- *pPacketHeaderStorage;
- PhysicalAddress pPacketHeaderStoragePhys;
- Ptr pIsochPacketHeader;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
-
- // Compute packet size by adding this and all subsequent send packets.
- packetSize = pDCLTransferPacketStart->size;
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacketStart->pNextDCLCommand;
- while (pDCLTransferPacket != nil)
- {
- if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) == kDCLSendPacketOp)
- {
- packetSize += pDCLTransferPacket->size;
- pDCLTransferPacket =
- (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
- }
- else
- {
- pDCLTransferPacket = nil;
- }
- }
-
- // Start new transmit PCL.
- status = LynxFWIMPCLNewIsochTransmit
- (pLynxPCLBuildState,
- (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
- (UInt32) pDCLTransferPacketStart,
- kLynxDMA100mbps);
-
- // Create packet header.
- if (status == noErr)
- packetHeader = packetSize << kFWIsochDataLengthPhase;
-
- // Allocate storage in PCL for header.
- if (status == noErr)
- {
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pPacketHeaderStorage);
- if (status == noErr)
- *pPacketHeaderStorage = packetHeader;
- // Now convert it to a physical address
- // I sure hope this was allocated in pLynxPCLBuildState->pCurrentPCL
- // Debug check below might not catch that
- // You know, maybe it would be better to make LynxFWIMPCLAllocateWord just return the
- // physical address. I think we always end up converting anyway. And it will be correct.
- pPacketHeaderStoragePhys = (PhysicalAddress)
- ((UInt32) pLynxPCLBuildState->pCurrentPCL->refCon +
- ((UInt32) pPacketHeaderStorage - (UInt32) pLynxPCLBuildState->pCurrentPCL));
-
- #ifdef LynxVMDebug
- if (((Ptr) (pPacketHeaderStorage)) !=
- ((Ptr) (pPacketHeaderStoragePhys)))
- {
- sprintf (debugStr, "Isoch header PTR (C) logical %08lx != physical %08lx",
- (long) pPacketHeaderStorage,
- (long) pPacketHeaderStoragePhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
-
- // Add packet size part of header buffer.
- if (status == noErr)
- {
- status = LynxFWIMPCLAddTransferBuffer
- (pLynxPCLBuildState,
- (Ptr) pPacketHeaderStoragePhys,
- 2,
- (Ptr *) &(pDCLTransferPacketStart->compilerData),
- kLynxPhysicalBuffer);
- }
-
- // Add rest of header buffer.
- if (status == noErr)
- {
- pIsochPacketHeader =
- (Ptr) (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
- status = LynxFWIMPCLAddTransferBuffer
- (pLynxPCLBuildState,
- pIsochPacketHeader + 2,
- 2,
- nil,
- kLynxPhysicalBuffer);
- }
-
- // Add payload buffer.
- if (status == noErr)
- {
- status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
- pDCLTransferPacketStart->buffer,
- pDCLTransferPacketStart->size,
- nil,
- kLynxLogicalBuffer);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddSendPacketWithHeaderStartDCL
- //
- // This proc adds a send packet with header start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacketStart;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
-
- // Start new transmit PCL.
- status = LynxFWIMPCLNewIsochTransmit
- (pLynxPCLBuildState,
- (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
- (UInt32) pDCLTransferPacketStart,
- kLynxDMA100mbps);
-
- // Add buffer.
- if (status == noErr)
- {
- status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
- pDCLTransferPacketStart->buffer,
- pDCLTransferPacketStart->size,
- nil,
- kLynxLogicalBuffer);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddSendPacketDCL
- //
- // This proc adds a send packet DCL.
- // zzz In case it doesn't get documented anywhere else, the DCL "SendPacket"
- // actually means send *part* of a packet. All consecutive SendPackets will
- // be merged together with the previous SendPacketStart, to form a single packet.
- // The same is true of ReceivePacket.
- //
-
- static OSStatus LynxFWIMAddSendPacketDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
-
- // Add buffer.
- status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- (Ptr *) &(pDCLTransferPacket->compilerData),
- kLynxLogicalBuffer);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddCallProcDCL
- //
- // This proc adds a call proc DCL.
- //
-
- static OSStatus LynxFWIMAddCallProcDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- OSStatus status = noErr;
-
- // Add an interrupt PCL.
- status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
- pDCLCommand,
- (Ptr *) &(pDCLCommand->compilerData));
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddJumpDCL
- //
- // This proc adds a jump DCL.
- //
-
- static OSStatus LynxFWIMAddJumpDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLJumpPtr pDCLJump;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLJump = (DCLJumpPtr) pDCLCommand;
-
- // Add a jump PCL.
- status = LynxFWIMPCLJump (pLynxPCLBuildState,
- pDCLJump->pJumpDCLLabel,
- (Ptr *) &(pDCLJump->compilerData));
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddLabelDCL
- //
- // This proc adds a label DCL.
- //zzz not optimal.
- //
-
- static OSStatus LynxFWIMAddLabelDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLLabelPtr pDCLLabel;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLLabel = (DCLLabelPtr) pDCLCommand;
-
- // Add a PCL label.
- status = LynxFWIMPCLLabel (pLynxPCLBuildState, pDCLLabel);
-
- // Resolve label.
- // This is complicated. If there were no PCL for a label DCL, we would want
- // to resolve things that point to us (pDCLCommand) to point to the PCL for
- // the next "real" command (a transmit, or whatever). But the next DCL has
- // not yet been compiled, (and it might be another label), so the PCL that we
- // would really like to point to doesn't exist yet.
- //
- // I think that what we do is have a dummy PCL that does correspond to this
- // label. That PCL just does a NOP and falls through to the next PCL (which
- // doesn't exist yet). That's what LynxFWIMPCLLabel created. So we waste a
- // PCL and add a little latency to jumps, because once we jump to this label
- // we have to fall through at least one dummy PCL before we get any work done.
- //
- // A possible future optimization would be to pre-allocate the next non-label
- // PCL, so that we know where it is and we can jump to it, rather than making
- // a dummy PCL as the target. That could be tricky because pre-allocation
- // could constrain us.
- //
- // A possible alternative optimization would be to take the finished PCL
- // program, and scan through it for jumps to NOPs, and bump them forward to
- // the next real command. That could also be tricky if we try to make changes
- // to the program later, though.
-
- if (status == noErr)
- status = LynxFWIMResolveDCLLabel (pDCLLabel);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAddSetTagSyncBitsDCL
- //
- // This proc adds a set tag and sync bits DCL.
- //
-
- static OSStatus LynxFWIMAddSetTagSyncBitsDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLSetTagSyncBitsPtr pDCLSetTagSyncBits;
- LynxPCLPtr pPCL;
- UInt32 currentBuffer;
- UInt32 *pIsochPacketHeader;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
-
- // Get current PCL.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Make sure we have at least two commands left in PCL.
- if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 3)) ||
- ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
- (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
- if (status == noErr)
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- }
-
- // Store location of PCL.
- if (status == noErr)
- {
- currentBuffer = pLynxPCLBuildState->currentBuffer;
- pDCLSetTagSyncBits->compilerData = (UInt32) &(pPCL->buffer[currentBuffer]);
- }
-
- // Get allocation for new isochronous packet header.
- if (status == noErr)
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pIsochPacketHeader);
-
- // Set up isochronous packet header.
- if (status == noErr)
- {
- *pIsochPacketHeader =
- (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
- (pLynxPCLBuildState->isochChannelNum << kFWIsochChanNumPhase) |
- (pDCLSetTagSyncBits->tagBits << kFWIsochTagPhase) |
- (pDCLSetTagSyncBits->syncBits << kFWIsochSyPhase);
- }
-
- // Load temp with new header.
- // Phys addr of allocated word can be derived from PCL base addr
- if (status == noErr)
- status = LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
- (Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
-
- #ifdef LynxVMDebug
- if (((Ptr) (pIsochPacketHeader)) !=
- ((Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL))))
- {
- sprintf (debugStr, "Isoch header PTR (B) logical %08lx != physical %08lx",
- (long) pIsochPacketHeader,
- (long) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
-
- // Store temp to engine data packet header (actually it's hidden in a PCL pool header).
- if (status == noErr)
- {
- pIsochPacketHeader =
- (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
- status = LynxFWIMPCLStoreTemp (pLynxPCLBuildState, (Ptr) pIsochPacketHeader);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMUpdateDCLListDCL
- //
- // This proc adds a update DCL list DCL.
- //
-
- static OSStatus LynxFWIMUpdateDCLListDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- OSStatus status = noErr;
-
- // Add an interrupt PCL.
- status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
- pDCLCommand,
- (Ptr *) &(pDCLCommand->compilerData));
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMTimeStampDCL
- //
- // This proc adds a time stamp DCL. This will build PCL commands to read the
- // current cycle counter and write it into the PCL command. The DCL compiler data
- // will point to where the cycle timer is stored in the PCL command.
- //
-
- static OSStatus LynxFWIMTimeStampDCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- LynxPCLPtr pPCL,
- physPCL;
- UInt32 *pPCLTimeStamp;
- OSStatus status = noErr;
-
- // Get current PCL.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Get Lynx FWIM data and pointer to link registers.
- pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Make sure we have at least three commands left in PCL.
- if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 4)) ||
- ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
- (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
- if (status == noErr)
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- }
-
- // Allocate word to store time stamp.
- if (status == noErr)
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &pPCLTimeStamp);
-
- // Save time stamp pointer in compiler data.
- if (status == noErr)
- pDCLCommand->compilerData = (UInt32) pPCLTimeStamp;
-
- // Add PCL command to read cycle timer register.
- if (status == noErr)
- {
- status = LynxFWIMPCLLoadTemp
- (pLynxPCLBuildState, (Ptr) &(pLynxRegs->cycleTimer));
- }
-
- // Add PCL command to write the cycle timer data into the PCL.
- if (status == noErr)
- {
- physPCL = (LynxPCLPtr) pPCL->refCon; // Get physical address of PCL.
- status = LynxFWIMPCLStoreTemp
- (pLynxPCLBuildState,
- (Ptr) ((UInt32) physPCL + ((UInt32) pPCLTimeStamp - (UInt32) pPCL)));
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLStart
- //
- // This proc creates a PCL build state record and a dummy PCL to start the
- // chain.
- //
-
- static OSStatus LynxFWIMPCLStart(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLBuildStatePtr *ppLynxPCLBuildState,
- LynxPCLPtr *ppPCL)
- {
- LynxPCLBuildStatePtr pLynxPCLBuildState;
- LynxPCLPtr pPCL;
- OSStatus status = noErr;
-
- // Allocate build state record.
- status = LynxFWIMAllocatePCLBuildState (pLynxFWIMData, &pLynxPCLBuildState);
-
- // Allocate start PCL.
- if (status == noErr)
- status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
-
- // Create start PCL.
- if (status == noErr)
- {
- pPCL->buffer[0].control =
- EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
- }
-
- // Fill in build state record.
- if (status == noErr)
- {
- pLynxPCLBuildState->pLynxFWIMData = pLynxFWIMData;
- pLynxPCLBuildState->pFirstPCL = pPCL;
- pLynxPCLBuildState->pCurrentPCL = pPCL;
- pLynxPCLBuildState->currentBuffer = 0;
- pLynxPCLBuildState->pclType = kLynxPCLStartType;
- pLynxPCLBuildState->refCon = 0;
- pLynxPCLBuildState->interrupt = false;
- }
-
- // Return results.
- if (status == noErr)
- {
- *ppLynxPCLBuildState = pLynxPCLBuildState;
- *ppPCL = pPCL;
- }
- else
- {
- *ppLynxPCLBuildState = nil;
- *ppPCL = nil;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLAllocateWord
- //
- // This proc allocates a word at the end of the current PCL.
- // The idea is to create a little storage space where we can keep data.
- // The space is at the end of the PCL so we don't try to execute it.
- // We might do a LOAD_TEMP from this location within the PCL (for example).
- //
-
- static OSStatus LynxFWIMPCLAllocateWord(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 **ppWord)
- {
- LynxPCLPtr pPCL;
- SInt32 lastBuffer;
- UInt32 bufferAllocationSize;
- UInt32 *pWord;
- OSStatus status = noErr;
-
- // Get some data out of build state.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- lastBuffer = pLynxPCLBuildState->lastBuffer;
- bufferAllocationSize = pLynxPCLBuildState->bufferAllocationSize;
-
- // Allocate word. We may have to extend PCL.
- if ((lastBuffer >= 13) || (bufferAllocationSize >= 2))
- {
- lastBuffer--;
- bufferAllocationSize = 0;
- }
- if (lastBuffer < pLynxPCLBuildState->currentBuffer)
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, pLynxPCLBuildState->pclType);
- if (status == noErr)
- {
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- lastBuffer = 12; //zzz should read back and reallocate if LynxFWIMPCLExtend can allocate a word.
- bufferAllocationSize = 0;
- }
- }
-
- if (status == noErr)
- {
- pWord = ((UInt32 *) (&(pPCL->buffer[lastBuffer].control))) +
- (1 - bufferAllocationSize);
- bufferAllocationSize++;
- }
-
- // Update build state.
- if (status == noErr)
- {
- pLynxPCLBuildState->lastBuffer = lastBuffer;
- pLynxPCLBuildState->bufferAllocationSize = bufferAllocationSize;
- }
-
- // Return results.
- if (status == noErr)
- *ppWord = pWord;
- else
- *ppWord = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLNew
- //
- // This proc creates a new logical PCL.
- //
-
- static OSStatus LynxFWIMPCLNew(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxPCLPtr pPCL,
- pPrevPCL;
- OSStatus status = noErr;
-
- // Get data from build state.
- pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
- pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Allocate new PCL.
- status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
-
- // Set up PCL.
- if (status == noErr)
- {
- pPCL->buffer[0].control =
- EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
- }
-
- // Link previous PCL.
- if ((status == noErr) &&
- (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
- {
- // Elsewhere we check pPCL to see if it's kLynxCPLINVALID before we
- // dereference it. But we just allocated pPCL so we know this one's safe.
- pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon); // Phys addr
- }
-
- // Update build state.
- if (status == noErr)
- {
- pLynxPCLBuildState->pFirstPCL = pPCL;
- pLynxPCLBuildState->pCurrentPCL = pPCL;
- pLynxPCLBuildState->currentBuffer = 0;
- pLynxPCLBuildState->lastBuffer = 13;
- pLynxPCLBuildState->bufferAllocationSize = 0;
- pLynxPCLBuildState->pclType = kLynxPCLUnknownType;
- // We didn't put refCon in the PCL itself (that space is used for the physical
- // address), but maybe the copy in the BuildState will be used - so preserve it:
- pLynxPCLBuildState->refCon = refCon;
- pLynxPCLBuildState->interrupt = false;
- }
-
- // Return results.
- if (status == noErr)
- *ppPCL = pPCL;
- else
- *ppPCL = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLNewIsochReceive
- //
- // This proc creates a new logical isochronous receive PCL.
- //zzz should we return PCL ptr?
- //
-
- static OSStatus LynxFWIMPCLNewIsochReceive(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon,
- UInt32 speed)
- {
- LynxPCLPtr pPCL;
- UInt32 commandWord;
- OSStatus status = noErr;
-
- // Create a new PCL.
- status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
-
- // Set pcl type and transfer command word.
- if (status == noErr)
- {
- // Build command word.
- commandWord = kLynxDMA_RCV << kLynxDMA_CMDPhase;
-
- pLynxPCLBuildState->pclType = kLynxPCLTransferType;
- pLynxPCLBuildState->commandWord = commandWord;
- }
-
- // Return results.
- if (status == noErr)
- *ppPCL = pPCL;
- else
- *ppPCL = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLNewIsochTransmit
- //
- // This proc creates a new logical isochronous transmit PCL.
- //
-
- static OSStatus LynxFWIMPCLNewIsochTransmit(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL,
- UInt32 refCon,
- UInt32 speed)
- {
- LynxPCLPtr pPCL;
- UInt32 commandWord;
- OSStatus status = noErr;
-
- // Create a new PCL.
- status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
-
- // Set pcl type and transfer command word.
- if (status == noErr)
- {
- // Build command word.
- commandWord = kLynxDMA_XMT << kLynxDMA_CMDPhase;
- commandWord |= speed << kLynxDMA_xmit_spd_codePhase;
- commandWord |= kLynxDMA_Tramsmit_ISO;
-
- // Before sending, "wait" for Ready == 1 Condition.
- // We actually use this to stop the active sender, between packets.
- // We never actually wait and then resume.
- commandWord |= (kLynxDMAWaitReady1 << kLynxDMA_WAIT_SELPhase);
-
- pLynxPCLBuildState->pclType = kLynxPCLTransferType;
- pLynxPCLBuildState->commandWord = commandWord;
- }
-
- // Return results.
- if (status == noErr)
- *ppPCL = pPCL;
- else
- *ppPCL = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLExtend
- //
- // This proc extends a logical PCL with another physical one.
- //zzz we should probably clear interrupts for previous PCL if interrupts are set
- //
-
- static OSStatus LynxFWIMPCLExtend(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 pclType)
- {
- LynxFWIMDataPtr pLynxFWIMData;
- LynxPCLPtr pPCL,
- pPrevPCL;
- OSStatus status = noErr;
-
- // Get data from build state.
- pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
- pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Cannot extend transfer PCLs into another tranfer PCL.
- if ((pLynxPCLBuildState->pclType == kLynxPCLTransferType) &&
- (pclType == kLynxPCLTransferType))
- {
- status = -1;//zzz what should it really be?
- }
-
- // Allocate new PCL.
- if (status == noErr)
- status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
-
- // Set up PCL.
- if (status == noErr)
- {
- pPCL->buffer[0].control =
- EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
- }
-
- // Link previous PCL.
- if ((status == noErr) &&
- (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
- {
- // No need to check for pPCL == kLynxCPLINVALID, because we just allocated it
- pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon); // Phys addr
- }
-
- // Update build state.
- if (status == noErr)
- {
- pLynxPCLBuildState->pCurrentPCL = pPCL;
- pLynxPCLBuildState->currentBuffer = 0;
- pLynxPCLBuildState->lastBuffer = 13;
- pLynxPCLBuildState->bufferAllocationSize = 0;
- pLynxPCLBuildState->pclType = pclType;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLLoadTemp
- //
- // This proc adds a load to the temp register command to the PCL program.
- //
-
- static OSStatus LynxFWIMPCLLoadTemp(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pSource)
- {
- OSStatus status = noErr;
-
- // pSource must by a physical address.
- // Whoever called us was reponsible for that
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_LOAD,
- 0,
- (UInt32) pSource);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLStoreTemp
- //
- // This proc adds a store from the temp register command to the PCL program.
- //
-
- static OSStatus LynxFWIMPCLStoreTemp(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest)
- {
- OSStatus status = noErr;
-
- // pDest must by a physical address.
- // Whoever called us was reponsible for that
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_STORE_QUAD,
- 0,
- (UInt32) pDest);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLStore0
- //
- // This proc adds a store 0 command to the PCL program.
- //
-
- static OSStatus LynxFWIMPCLStore0(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest)
- {
- OSStatus status = noErr;
-
- // pDest must by a physical address.
- // Whoever called us was reponsible for that
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_STORE0,
- 0,
- (UInt32) pDest);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLStore1
- //
- // This proc adds a store 1 command to the PCL program.
- //
-
- static OSStatus LynxFWIMPCLStore1(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr pDest)
- {
- OSStatus status = noErr;
-
- // pDest must by a physical address.
- // Whoever called us was reponsible for that
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_STORE1,
- 0,
- (UInt32) pDest);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLCompareTemp16WithMask
- //
- // This proc adds a 16 bit compare with mask command.
- //
-
- static OSStatus LynxFWIMPCLCompareTemp16WithMask(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt16 compareValue,
- UInt16 compareMask)
- {
- OSStatus status = noErr;
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_COMPARE,
- 0,
- (UInt32) ((compareMask << 16) | compareValue));
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLBranchIfEqual
- //
- // This proc adds a branch if equal command.
- //
-
- static OSStatus LynxFWIMPCLBranchIfEqual(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel)
- {
- LynxPCLPtr pCurrentPCL,
- pDCLLabelPCL;
- UInt32 currentBuffer;
- UInt32 branchTargetPhys;
- OSStatus status = noErr;
-
- // Check if label has been resolved.
- if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
- {
- // The label has been resolved, so we can determine the actual
- // (physical) address of the PCL to jump to. Put that in the
- // PCL we are writing, and we're all set.
-
- // pDCLLabelPCL can be kLynxCPLINVALID (0x00000001) if the branch
- // target is a phony DCL (ie stop on condition). Don't lookup
- // a physical address for 1.
- // (Branching to kLynxCPLINVALID will cause the DMA to halt safely.)
-
- if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
- branchTargetPhys = kLynxCPLINVALID;
- else branchTargetPhys = pDCLLabelPCL->refCon;
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_BRANCH,
- kLynxAuxConditionDMAReady1,
- branchTargetPhys);
-
- #ifdef LynxVMDebug
- if (((Ptr) (pDCLLabelPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "BranchIfEqual target logical %08lx != physical %08lx",
- (long) pDCLLabelPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
- else
- {
- // The DCL we are jumping to has not yet been compiled into a PCL.
- // So make a note in the DCL's compilerData of the (logical) address
- // where the PCL branch target's (physical) address should go.
- // This will be updated with the target DCL gets compiled. Note that
- // compilerData (in the targed DCL) may already contain a reference,
- // so copy that to our (yet unused) physical target, and replace it
- // with our own pointer. This creates a list (of sorts) of references.
-
- status = LynxFWIMPCLAuxCommand
- (pLynxPCLBuildState,
- kLynxDMA_BRANCH,
- kLynxAuxConditionDMAReady1,
- (UInt32) pDCLLabel->compilerData);
-
- // Need to resolve label later.
- if (status == noErr)
- {
- pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
- currentBuffer = pLynxPCLBuildState->currentBuffer;
-
- // Stash in the target DCL the (logical) address where the
- // (physical) PCL target will need to go, once it is known.
-
- pDCLLabel->compilerData =
- (UInt32) &(pCurrentPCL->buffer[currentBuffer - 1].address);
- }
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLJump
- //
- // This proc sets the current PCL to jump to the given label.
- //zzz we should probably start a new PCL so any subsequent DCLs are not run as
- //zzz a part of the current PCL.
- //
-
- static OSStatus LynxFWIMPCLJump(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel,
- Ptr *ppPCLCommand)
- {
- LynxPCLPtr pCurrentPCL,
- pDCLLabelPCL;
- UInt32 branchTargetPhys;
- OSStatus status = noErr;
-
- // Get current PCL.
- pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Return PCL.
- if (ppPCLCommand != nil)
- *ppPCLCommand = (Ptr) pCurrentPCL;
-
- // Check if label has been resolved.
- if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
- {
- // It would be legal to load ->nextPCL with kLynxCPLINVALID.
- // I don't think that ever happens, but do the right thing if so:
-
- if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
- branchTargetPhys = kLynxCPLINVALID;
- else branchTargetPhys = pDCLLabelPCL->refCon;
-
- pCurrentPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit (branchTargetPhys);
- #ifdef LynxVMDebug
- if (((Ptr) (pDCLLabelPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Jump target logical %08lx != physical %08lx",
- (long) pDCLLabelPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
- else
- {
- // In case the DCL we're branching to already has one unresolved
- // reference, store that one in our branch field so we can put our
- // own address in the DCL. See next comment.
- pCurrentPCL->nextPCL =
- (UInt32 *) EndianSwap32Bit ((UInt32) pDCLLabel->compilerData);
-
- // Need to resolve label later.
- // This is tricky. Store the (logical) address of the (physical) jump
- // target address in compilerData. Later, we'll update it. Note that
- // if the spot to be updated contains another address (from previous
- // line) then we'll update that one too, and so on.
- pDCLLabel->compilerData = (UInt32) &(pCurrentPCL->nextPCL);
-
- // The resolution of all this is done by LynxFWIMResolveDCLLabel.
- // Labels are resolved as soon as they are added, but we might be
- // branching to a label that hasn't yet been added (it follows us).
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLInterrupt
- //
- // This proc adds a command to issue an interrupt and add a link to the interrupt queue.
- // This will create a PCL to store the current queue tail into the PCL. This PCL
- // will then set the queue tail to point into the PCL.
- //
- // LOAD_TMP
- // interrupt_queue_tail
- //
- // STORE_TMP
- // PCL_queue_link
- //
- // LOAD_TMP
- // PCL_queue_link_logical_ptr
- //
- // STORE_TMP
- // interrupt_queue_tail
- //
- // PCL_queue_link_logical_ptr: &PCL_queue_link
- // {
- // PCL_queue_link: quad storage
- // DCL_logical_ptr: &DCL
- // } LynxDCLProgramInterruptQueueElement;
- //
-
- static OSStatus LynxFWIMPCLInterrupt(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLCommandPtr pDCLCommand,
- Ptr *ppPCLCommand)
- {
- LynxFWIMDataPtr pLynxFWIMData,
- physLynxFWIMData;
- LynxPCLPtr pPCL,
- physPCL;
- DCLCommandPtr *ppDCLCommand;
- LynxDCLProgramInterruptQueueElementPtr
- *ppDCLInterruptLink,
- *ppDCLInterrupt;
- UInt32 pclChannelNum;
- UInt32 currentBuffer;
- UInt32 bufferNum;
- OSStatus status = noErr;
-
- // Set interrupt flag in build state.
- pLynxPCLBuildState->interrupt = true;
-
- // Get current PCL.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
-
- // Make sure we have at least six commands left in PCL.
- if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 7)) ||
- ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
- (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
- if (status == noErr)
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- }
-
- // Set interrupt bit in preceeding commands.
- //zzz should only have to do it for first command.
- if (status == noErr)
- {
- currentBuffer = pLynxPCLBuildState->currentBuffer;
- for (bufferNum = 0; bufferNum < currentBuffer; bufferNum++)
- pPCL->buffer[bufferNum].control |= EndianSwapImm32Bit (kLynxDMA_INT);
- }
-
- // Return pointer to command.
- if ((status == noErr) && (ppPCLCommand != nil))
- *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
-
- // Get Lynx FWIM data.
- pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
- physLynxFWIMData = (LynxFWIMDataPtr) pLynxFWIMData->fwimDataPhys;
-
- // Get physical address of current PCL.
- physPCL = (LynxPCLPtr) pPCL->refCon;
-
- // Allocate a word (DCL_logical_ptr) to hold logical pointer to the DCL.
- if (status == noErr)
- {
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLCommand);
- if (status == noErr)
- *ppDCLCommand = pDCLCommand;
- }
-
- // Allocate a word (PCL_queue_link) to save interrupt queue link.
- if (status == noErr)
- {
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState,
- (UInt32 **) &ppDCLInterruptLink);
- }
-
- // Allocate a word (PCL_queue_link_logical_ptr) to hold logical pointer to
- // PCL's LynxDCLProgramInterruptQueueElement.
- if (status == noErr)
- {
- status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLInterrupt);
- if (status == noErr)
- *ppDCLInterrupt = (LynxDCLProgramInterruptQueueElementPtr) ppDCLInterruptLink;
- }
-
- // Load the interrupt queue tail.
- // LOAD_TMP
- // interrupt_queue_tail
- if (status == noErr)
- {
- pclChannelNum = pLynxPCLBuildState->pclChannelNum;
- status = LynxFWIMPCLLoadTemp
- (pLynxPCLBuildState,
- (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
- }
-
- // Store the interrupt queue tail into interrupt queue element link.
- // STORE_TMP
- // PCL_queue_link
- if (status == noErr)
- {
- status =
- LynxFWIMPCLStoreTemp
- (pLynxPCLBuildState,
- (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterruptLink - (UInt32) pPCL)));
- }
-
- // Load pointer to our interrupt queue element.
- // LOAD_TMP
- // PCL_queue_link_logical_ptr
- if (status == noErr)
- {
- status =
- LynxFWIMPCLLoadTemp
- (pLynxPCLBuildState,
- (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterrupt - (UInt32) pPCL)));
- }
-
- // Store pointer to our interrupt queue element into interrupt queue tail.
- if (status == noErr)
- {
- status = LynxFWIMPCLStoreTemp
- (pLynxPCLBuildState,
- (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLAuxCommand
- //
- // This proc adds the given auxiliary command to the PCL program.
- // Branching is dependent upon the way currentBuffer is set.
- //zzz need to special case if prior PCL was async send
- //
- // In many cases, auxParam is a physical address. Whoever calls us
- // must have worked it out in advance.
- //
-
- static OSStatus LynxFWIMPCLAuxCommand(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- UInt32 auxCommand,
- UInt32 waitBranchCondition,
- UInt32 auxParam)
- {
- LynxPCLPtr pPCL;
- UInt32 pclType;
- UInt32 currentBuffer;
- UInt32 commandWord;
- OSStatus status = noErr;
-
- // Get data from build state.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- pclType = pLynxPCLBuildState->pclType;
- currentBuffer = pLynxPCLBuildState->currentBuffer;
-
- // Check if we need to extend PCL.
- if (((pclType != kLynxPCLAuxType) &&
- (pclType != kLynxPCLUnknownType)) ||
- (currentBuffer == pLynxPCLBuildState->lastBuffer))
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
- if (status == noErr)
- {
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- pclType = kLynxPCLAuxType;
- currentBuffer = 0;
- }
- }
-
- // Set PCL type to kLynxPCLAuxType if it's unknown.
- if ((status == noErr) && (pclType == kLynxPCLUnknownType))
- pLynxPCLBuildState->pclType = kLynxPCLAuxType;
-
- // If we're not on the first command, clear last command last buf bit.
- if ((status == noErr) && (currentBuffer > 0))
- pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
-
- // Add command.
- if (status == noErr)
- {
- // Build command word.
- commandWord = auxCommand << kLynxDMA_CMDPhase;
- commandWord |= waitBranchCondition << kLynxDMA_BRANCH_SELPhase;
- commandWord |= kLynxDMA_LAST_BUF;
- if (pLynxPCLBuildState->interrupt)
- commandWord |= kLynxDMA_INT;
-
- // Add it.
- pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
- // See above - sometimes this is a physical address
- pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit (auxParam);
- pLynxPCLBuildState->currentBuffer++;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLAddTransferBuffer
- //
- // This proc adds the given transfer buffer to the PCL program. It will
- // return a pointer to the PCL command if ppPCLCommand is non-nil.
- // Branching is dependent upon the way currentBuffer is set.
- //zzz need to special case if prior PCL was async send
- //
-
- static OSStatus LynxFWIMPCLAddTransferBuffer(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- Ptr buffer,
- UInt32 bufferSize,
- Ptr *ppPCLCommand,
- UInt32 bufferAddrType)
- {
- LynxPCLPtr pPCL;
- UInt32 pclType;
- UInt32 currentBuffer;
- UInt32 commandWord;
- PhysicalAddress physAddrs[4]; // enough for 800 mbits
- UInt32 pageCount, pageSize, firstPageSize;
- OSStatus status = noErr;
-
- // Get data from build state.
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- pclType = pLynxPCLBuildState->pclType;
- currentBuffer = pLynxPCLBuildState->currentBuffer;
-
- // Check if we're at the end of the PCL.
- // Can't transfer accross multiple PCLs.
- // For now, assume we'll need at most two slots for page crossing.
- // That handles packets up to 4097 bytes.
- // At 200 mbits, max isoch packet is 2500.
- // A 400 mbit channel > 80% reservation can break us.
-
- if ((pclType == kLynxPCLTransferType) &&
- (currentBuffer + 1 >= pLynxPCLBuildState->lastBuffer))
- {
- status = -1;//zzz what should it really be?
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMPCLAddTransferBuffer - failed due to full PCL");
- }
-
- // Check if we need to extend PCL.
- if ((status == noErr) &&
- (pclType != kLynxPCLTransferType) &&
- (pclType != kLynxPCLUnknownType))
- {
- status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLTransferType);
- if (status == noErr)
- {
- pPCL = pLynxPCLBuildState->pCurrentPCL;
- currentBuffer = 0;
- }
- }
-
- // Set PCL type to kLynxPCLTransferType if it's unknown.
- if ((status == noErr) && (pclType == kLynxPCLUnknownType))
- pLynxPCLBuildState->pclType = kLynxPCLTransferType;
-
- // If we're not on the first command, clear last command last buf bit.
- // Also clear the wait condition on the current command, if transmit.
- if ((status == noErr) && (currentBuffer > 0))
- {
- pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
-
- // Seems like there ought to be a better way to do this.
- // Note, duplicated below in page-crossing case
- if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
- pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
- }
-
- // When VM is turned on, we may have to translate the provided buffer into a physical
- // address. If the buffer straddles a page boundary, we may need two (or more)
- // buffers (>2 buffers only possible at 400 megabits or above). We built a lookup
- // table of logical/physical buffers before we started compling, so we use a lookup
- // function now. Also note that there can be more than one DCL in this PCL. For
- // example, a PacketStart DCL followed by a Packet DCL (for isoch transmit) must be
- // merged into a single PCL (Lynx allows only one PCL per packet)
-
- // Finally, keep in mind that the buffers may be updated later, and the number of
- // page boundary crossings may change. But, the upper bound is low - no more than
- // two crossings at 400 mbits. However, if the user assembles a transmit packet
- // out of many small buffers, we don't want to waste slots in the PCL. Also some
- // PCL slots may be used up by AUX commands and inline data.
-
- // Some buffers are already physical (they point to Lynx registers, PCLs, or other
- // data we already prepared as physical).
-
- // Add command.
- if (status == noErr)
- {
- // Add it.
- if (bufferAddrType == kLynxPhysicalBuffer)
- {
- // If it's a physical buffer, it doesn't matter if we cross page boundaries.
- // We can do it all with a single transfer command. (Physical buffers are
- // usually only 2 (maybe 4) bytes, last I checked.)
-
- // Build command word.
- commandWord = pLynxPCLBuildState->commandWord;
- commandWord |= bufferSize << kLynxDMA_TransferCountPhase;
- commandWord |= kLynxDMA_LAST_BUF;
- pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
- pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) buffer);
-
- pLynxPCLBuildState->currentBuffer++;
- }
- else // logical buffer
- {
- pageCount = LynxFWIMDataMapToPhysical (pLynxPCLBuildState->pLynxDCLCompilerEngineData,
- buffer, bufferSize, physAddrs);
- #ifdef LynxVMDebug
- if (((Ptr) (buffer)) !=
- ((Ptr) (physAddrs[0])))
- {
- sprintf (debugStr, "Payload lookup logical %08lx != physical %08lx",
- (long) buffer,
- (long) physAddrs[0]);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- if (pageCount > 2)
- FWDebugStr ((ConstStr255Param) "\pOops, too many pages for DMA (?!)");
-
- // Should cache this or make lookup figure it all out for us
- pageSize = GetLogicalPageSize ();
-
- // Make this all work regardless of page size and speed. Who knows what might change.
- if (pageCount == 1)
- firstPageSize = bufferSize;
- else
- firstPageSize = pageSize - ((UInt32) buffer & (pageSize - 1));
-
- // Build command word.
- commandWord = pLynxPCLBuildState->commandWord;
- commandWord |= firstPageSize << kLynxDMA_TransferCountPhase;
- if (pageCount == 1) commandWord |= kLynxDMA_LAST_BUF;
- pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
- pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[0]);
-
- // We are now mid-packet. Clear wait from here to end of packet.
- // (duplicated above)
- if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
- pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
-
- if (pageCount > 1) // assume it's 2
- {
- // Build command word.
- commandWord = pLynxPCLBuildState->commandWord;
- commandWord |= (bufferSize - firstPageSize) << kLynxDMA_TransferCountPhase;
- commandWord |= kLynxDMA_LAST_BUF;
- pPCL->buffer[currentBuffer + 1].control = EndianSwap32Bit (commandWord);
- pPCL->buffer[currentBuffer + 1].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[1]);
- }
-
- pLynxPCLBuildState->currentBuffer += pageCount;
- }
-
- // Return pointer to command.
- if (ppPCLCommand != nil)
- *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
-
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMResolveDCLLabel
- //
- // This proc resolves the given DCL label.
- //
-
- static OSStatus LynxFWIMResolveDCLLabel(
- DCLLabelPtr pDCLLabel)
- {
- DCLCommandPtr pDCLCommand;
- LynxPCLPtr pPCL,
- *pLabelDependency,
- *pNextLabelDependency;
- UInt32 branchTargetPhys;
- OSStatus status = noErr;
-
- // The label pDCLLabel has just been added to the PCL program. It may already
- // be the branch target of one or more existing PCLs. If so, they have stashed
- // a pointer to where they hold their branch target in pDCLLabel->compilerData.
- // Furthermore, if what is pointed to is not nil, it is another pointer to an
- // unresolved label, etc. So we follow that chain, filling in our real PCL
- // address. Note that we will need to fill in the physical address, since now
- // is the final stage in assigning jump addresses.
-
- // Resolve all of the dependencies.
- if (pDCLLabel->compilerData != nil)
- {
- // Get PCL for this label.
- // PCL will be the PCL for the next non label DCL.
- //zzz what if label DCL is last in list???
- pDCLCommand = pDCLLabel->pNextDCLCommand;
- while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- pPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
-
- // Resolve label to this PCL.
- if (pPCL != nil)
- {
- pLabelDependency = (LynxPCLPtr *) pDCLLabel->compilerData;
- while (pLabelDependency != nil)
- {
- // Sometimes we branch to kLynxCPLINVALID in order to stop the DMA.
- // I'm not sure if that can happen here, but just in case, check
- // pPCL for kLynxCPLINVALID before dereferencing it.
-
- if (pPCL == (LynxPCLPtr) kLynxCPLINVALID)
- branchTargetPhys = kLynxCPLINVALID;
- else branchTargetPhys = pPCL->refCon;
-
- pNextLabelDependency = (LynxPCLPtr *) *pLabelDependency;
- *pLabelDependency = (LynxPCLPtr) EndianSwap32Bit (branchTargetPhys);
- pLabelDependency = pNextLabelDependency;
- #ifdef LynxVMDebug
- if (((Ptr) (pPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Resolved target logical %08lx != physical %08lx",
- (long) pPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
- }
- pDCLLabel->compilerData = nil;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMGetDCLLabelPCLPtr
- //
- // This proc returns a pointer to the PCL corresponding to the given label
- // if the given label is resolved. A return value of nil means the label has
- // not been resolved.
- //
-
- static LynxPCLPtr LynxFWIMGetDCLLabelPCLPtr(
- DCLLabelPtr pDCLLabel)
- {
- DCLCommandPtr pDCLCommand;
- LynxPCLPtr pDCLLabelPCL;
-
- // Search for next command that is not another label.
- pDCLCommand = pDCLLabel->pNextDCLCommand;
- while (pDCLCommand != nil)
- {
- if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- else
- break;
- }
-
- // Return results.
- if (pDCLCommand != nil)
- pDCLLabelPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
- else
- pDCLLabelPCL = (LynxPCLPtr) kLynxCPLINVALID;
-
- return (pDCLLabelPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMPCLLabel
- //
- // This proc adds a DCL label to the PCL program.
- //
-
- static OSStatus LynxFWIMPCLLabel(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- DCLLabelPtr pDCLLabel)
- {
- DCLCommandPtr pDCLCommand;
- LynxPCLPtr pPCL;
- OSStatus status = noErr;
-
- // We don't need to do anything if this label already has a PCL associated
- // with it.
- if (LynxFWIMGetDCLLabelPCLPtr (pDCLLabel) == nil)
- {
- // Start new PCL.
- status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, (UInt32) pDCLLabel);
-
- // Set next non label DCL's compiler data to the new PCL.
- // When the next non label DCL is compiled, its compiler data will be updated
- // to point to the PCL command within the PCL created above.
- //zzz what if label is last in program?
- if (status == noErr)
- {
- pDCLCommand = pDCLLabel->pNextDCLCommand;
- while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- pDCLCommand->compilerData = (UInt32) pPCL;
- }
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMGetPCLFromDCL
- //
- // This proc returns a pointer to the start of the PCL corresponding to the
- // given DCL. Label DCLs do not have corresponding PCLs.
- //zzz well, label DCLs do, so maybe we should integrate LynxFWIMGetDCLLabelPCLPtr
- //zzz with this routine
- //
-
- static LynxPCLPtr LynxFWIMGetPCLFromDCL(
- DCLCommandPtr pDCLCommand)
- {
- LynxPCLPtr pPCL;
-
- // Base of PCL is the compiler data masked with kPCLAlignmentMask.
- pPCL = (LynxPCLPtr) (pDCLCommand->compilerData & kPCLAlignmentMask);
-
- // I have a lingering suspicion that I might have done something wrong
- // here that can (rarely) cause a physical PCL pointer to get dereferenced.
- // But I only saw it happen once and I wasn't really paying attention,
- // so maybe it was just a fluke.
-
- return (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDCLCompilerNotification
- //
- // This proc handles update notifications for the DCL to PCL compiler.
- //
-
- static OSStatus LynxFWIMDCLCompilerNotification(
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- OSStatus status = noErr;
-
- switch (notificationType)
- {
- case kFWDCLUpdateNotification :
- status = LynxFWIMDCLCompilerUpdateNotification (dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- case kFWDCLModifyNotification :
- status = LynxFWIMDCLCompilerModifyNotification (dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- default :
- status = paramErr;
- break;
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDCLCompilerUpdateNotification
- //
- // This proc handles update notifications for the DCL to PCL compiler. This will
- // do any neccessary CheckPointIOs and update any DCL status fields.
- //zzz do the right stuff in here
- //
-
- static OSStatus LynxFWIMDCLCompilerUpdateNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- UInt32 dclCommandNum;
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- pDCLCommand = dclCommandList[dclCommandNum];
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLTimeStampOp :
- LynxFWIMUpdateDCLTimeStamp (pDCLCommand);
- break;
-
- default :
- break;
- }
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMUpdateDCLTimeStamp
- //
- // This proc updates a DCL time stamp. It reads the time stamp out of a PCL
- // and writes it into the timeStamp field of the DCL.
- //
-
- static OSStatus LynxFWIMUpdateDCLTimeStamp(
- DCLCommandPtr pDCLCommand)
- {
- DCLTimeStampPtr pDCLTimeStamp;
- UInt32 *pTimeStamp;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
-
- // Copy time stamp from PCL.
- // Add one cycle since we're running ahead.
- //zzz have to be able to compute run ahead. It can vary depending upon packet size.
- pTimeStamp = (UInt32 *) pDCLTimeStamp->compilerData;
- pDCLTimeStamp->timeStamp = EndianSwap32Bit (*pTimeStamp) + (1 << 12);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDCLCompilerModifyNotification
- //
- // This proc handles modification notifications for the DCL to PCL compiler.
- //zzz break this routine up
- //
-
- static OSStatus LynxFWIMDCLCompilerModifyNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- DCLJumpPtr pDCLJump;
- DCLLabelPtr pDCLLabel;
- LynxPCLPtr pJumpPCL,
- pLabelPCL;
-
- DCLTransferPacketPtr pDCLTransferPacket;
- LynxPCLPtr pTransferPacketPCL;
- UInt32 pclControl;
- UInt32 dclCommandNum;
- UInt32 branchTargetPhys;
-
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- // Get DCL command to update.
- pDCLCommand = *dclCommandList++;
-
- // Update command.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLJumpOp :
-
- // Recast.
- pDCLJump = (DCLJumpPtr) pDCLCommand;
-
- // Get label we're jumping to.
- pDCLLabel = pDCLJump->pJumpDCLLabel;
-
- // Get PCLs for jump and label DCLs.
- pJumpPCL = LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLJump);
- pLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel);
-
- if (pLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
- branchTargetPhys = kLynxCPLINVALID;
- else
- branchTargetPhys = pLabelPCL->refCon;
-
- // Update jump PCL.
- pJumpPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) branchTargetPhys);
-
- #ifdef LynxVMDebug
- if (((Ptr) (pLabelPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Updated jump logical %08lx != physical %08lx",
- (long) pLabelPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- //zzz support other transfer packet commands.
-
- FWDebugStr ((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
-
- // What would we do?
- // We can't do what's done below - that fills in new PCL buffer addresses. They aren't yet known.
- // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme. I notice that
- // we don't actually modify the base DCLs - I think we will have to do that. So make one pass to
- // modify the base DCLs. Then call the general-purpose memory preparation routine, and let it
- // create an all-new ioPrep (keep the old one). Once that's done, we can re-scan the list of
- // changes and make updates knowing the new physical addresses. Finally, once the updates are
- // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
- // the old ioPrep struct and free its resources. [Technically we should wait one packet to make
- // sure that whatever Lynx's current DMA engine is doing is up to date. Probably a good-enough
- // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
- // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
- //
- // We should find a safe way to make multiple updates to a PCL. The user is in trouble anyway
- // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
- // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
- // (could be bad for Lynx). Perhaps we should copy command[0], set it to NOP+last, update the
- // others, then update command[0]. That's safe unless we are inside the PCL but past command[0].
- // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
- //
- // I don't suppose the user is required to use jump-updates to deactivate part of the program
- // before updating that part? That would be 100% safe if we know the jump-update worked on time.
- //
- // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
- // structs, then we don't have to do any allocs here. (though PrepareMemForIO might anyway).
- // We know that the total number of buffers can't change, so rangeTable is OK. When we prepare
- // the physAddr table we should work out both the true size and the worst-case size. Use the
- // worst-case for alloc, use the true for PrepareMemoryForIO
-
- // Recast.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
-
- // Get PCL.
- pTransferPacketPCL =
- LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
-
- // Update buffer size of transfer PCL.
- pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
- pclControl = (pclControl & ~kLynxDMA_TransferCount) |
- ((pDCLTransferPacket->size) << kLynxDMA_TransferCountPhase);
- pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
-
- // Update buffer address of transfer PCL.
- // WARNING WARNING this won't work with VM on - this is a logical address
- pTransferPacketPCL->buffer[0].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
-
- break;
-
- default :
-
- break;
- }
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAllocatePCLBuildState
- //
- // This proc allocates a PCL build state record.
- //zzz we really don't need this. should be allocated by other methods (stack?)
- //
-
- static OSStatus LynxFWIMAllocatePCLBuildState(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLBuildStatePtr *ppLynxPCLBuildState)
- {
- LynxPCLBuildStatePtr pLynxPCLBuildState;
- OSStatus status = noErr;
-
- // Allocate memory for record.
- pLynxPCLBuildState =
- (LynxPCLBuildStatePtr) PoolAllocateResident (sizeof (LynxPCLBuildState), true);
- if (pLynxPCLBuildState == nil)
- status = memFullErr;
-
- // Return results.
- if (status == noErr)
- *ppLynxPCLBuildState = pLynxPCLBuildState;
- else
- *ppLynxPCLBuildState = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAllocatePCL
- //
- // This proc allocates a PCL.
- //
-
- static OSStatus LynxFWIMAllocatePCL(
- LynxPCLBuildStatePtr pLynxPCLBuildState,
- LynxPCLPtr *ppPCL)
- {
- LynxPCLPoolDataPtr pLynxPCLPoolData;
- LynxPCLPtr pPCL,
- pclPool;
- UInt32 pclPoolPhys;
- UInt32 nextFreePCL;
- IOPreparationTable *ioPrep;
- UInt32 pageSize, allocSize;
- Ptr p;
- OSStatus status = noErr;
-
- // Get PCL pool data record.
- pLynxPCLPoolData = pLynxPCLBuildState->pLynxPCLPoolDataList;
-
- // Get PCL pool and next free PCL index.
- if (pLynxPCLPoolData != nil)
- {
- pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
- pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
- nextFreePCL = pLynxPCLPoolData->nextFreePCL;
- }
- else
- {
- pclPool = nil;
- }
-
- // Allocate new pool if current pool is exhausted.
- // This pool needs to be aligned to the PCL size for the PCL compilation logic
- // to work properly. Pool size can exceed one phys page as long as we have an
- // allocator which gives us contiguous pages.
-
- if ((pclPool == nil) || (nextFreePCL >= kPCLPoolSize))
- {
- pageSize = GetLogicalPageSize ();
- allocSize = sizeof (LynxPCLPoolData) + sizeof (LynxPCL);
-
- // Not knowing if MemAllocPhysCont returns page-aligned data, we need to
- // add one page to align and one more to flush out the end of the struct.
- // (Could be done more tightly.)
-
- allocSize = (allocSize / pageSize) + 3; // sloppy
-
- p = MemAllocatePhysicallyContiguous (allocSize * pageSize, true);
- if (p != nil)
- {
- // Page align
- pLynxPCLPoolData = (LynxPCLPoolDataPtr)
- (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));
-
- // Store original
- pLynxPCLPoolData->poolAllocatedAddress = (LogicalAddress) p;
-
- ioPrep = &pLynxPCLPoolData->ioPrep;
-
- // Prepare for IO and get physical address
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = allocSize - 1; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = pLynxPCLPoolData->physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.range.base = (void *) pLynxPCLPoolData;
- ioPrep->rangeInfo.range.length = (allocSize - 1) * pageSize;
-
- // The CheckpointIO is in LynxFWIMDeallocatePCLPools
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "PCL Pool PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pLynxPCLPoolData->physAddrs[0],
- (long) ioPrep->rangeInfo.range.length);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- pLynxPCLPoolData->pNextLynxPCLPoolData =
- pLynxPCLBuildState->pLynxPCLPoolDataList;
- pLynxPCLBuildState->pLynxPCLPoolDataList = pLynxPCLPoolData;
- // Never use pclPoolDummy. (This is the only place) It does not index
- // the true aligned PCLs. Use alignedPCLPoolBase as an array instead.
- pLynxPCLPoolData->alignedPCLPoolBase = (LynxPCLPtr)
- (((UInt32) &(pLynxPCLPoolData->pclPoolDummy[1])) & kPCLAlignmentMask);
-
- pLynxPCLPoolData->alignedPCLPoolBasePhys =
- (UInt32) pLynxPCLPoolData->physAddrs[0] +
- ((UInt32) pLynxPCLPoolData->alignedPCLPoolBase - (UInt32) pLynxPCLPoolData);
-
- // In the first allocated pool, we keep space for the isoch packet
- // header (for transmit). Work out its location and store it away.
- // Note we only really need to do this the first time. Note also
- // that whoever is going to use this better make a copy before the
- // second time we come here.
-
- pLynxPCLPoolData->isochPacketHeaderPhys = (PhysicalAddress)
- ((UInt32) pLynxPCLPoolData->physAddrs[0] +
- ((UInt32) &(pLynxPCLPoolData->isochPacketHeader) - (UInt32) pLynxPCLPoolData));
-
- #ifdef LynxVMDebug
- if (((Ptr) (&(pLynxPCLPoolData->isochPacketHeader))) !=
- ((Ptr) (pLynxPCLPoolData->isochPacketHeaderPhys)))
- {
- sprintf (debugStr, "Isoch header store logical %08lx != physical %08lx",
- (long) (&(pLynxPCLPoolData->isochPacketHeader)),
- (long) pLynxPCLPoolData->isochPacketHeaderPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- nextFreePCL = 0;
- pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
- pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
- }
- else
- {
- status = memFullErr;
- }
- }
-
- // Allocate PCL from pool.
- if (status == noErr)
- {
- pPCL = &(pclPool[nextFreePCL++]);
- pPCL->refCon = pclPoolPhys + (((UInt32) pPCL) - ((UInt32) pclPool));
- pLynxPCLPoolData->nextFreePCL = nextFreePCL;
- #ifdef LynxVMDebug
- if (((Ptr) (pPCL)) != ((Ptr) (pPCL->refCon)))
- {
- sprintf (debugStr, "PCL alloc logical %08lx != physical %08lx",
- (long) pPCL,
- (long) pPCL->refCon);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
-
- // Initialize the PCL.
- if (status == noErr)
- {
- pPCL->nextPCL = (UInt32 *) EndianSwap32Bit (kLynxCPLINVALID);
- pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
- pPCL->status = EndianSwapImm32Bit (0);
- pPCL->remaining = EndianSwapImm32Bit (0);
- pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
- }
-
- // Return results.
- if (status == noErr)
- *ppPCL = pPCL;
- else
- *ppPCL = nil;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDeallocatePCLPools
- //
- // This proc deallocates the given list of PCL pools.
- //
-
- static void LynxFWIMDeallocatePCLPools(
- LynxPCLPoolDataPtr pLynxPCLPoolDataList)
- {
- LynxPCLPoolDataPtr pLynxPCLPoolData,
- pNextLynxPCLPoolData;
- OSStatus status = noErr;
-
- // Deallocate each pool in list.
- pLynxPCLPoolData = pLynxPCLPoolDataList;
- while (pLynxPCLPoolData != nil)
- {
- pNextLynxPCLPoolData = pLynxPCLPoolData->pNextLynxPCLPoolData;
- status = CheckpointIO (pLynxPCLPoolData->ioPrep.preparationID, kNilOptions);
- if (status != noErr)
- {
- sprintf (debugStr, "PCL Pool CheckpointIO status %ld ID was %08lx",
- (long) status,
- (long) pNextLynxPCLPoolData->ioPrep.preparationID);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- if (MemDeallocatePhysicallyContiguous (pLynxPCLPoolData->poolAllocatedAddress) != noErr)
- FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
- pLynxPCLPoolData = pNextLynxPCLPoolData;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMRunDCLProgram
- //
- // This proc uses the given packet to run through the DCL program.
- // This is obsolete, but shows how one could manually process DCLs.
- //
-
- static void LynxFWIMRunDCLProgram(
- LynxIsochPortDataPtr pLynxIsochPortData,
- Ptr packetBuffer,
- UInt32 packetSize,
- DCLCommandPtr *ppDCLCommand)
- {
- DCLCommandPtr pDCLCommand;
- DCLCallProcPtr pDCLCallProc;
- DCLJumpPtr pDCLJump;
- UInt32 packetSizeLeft;
- Boolean waitForPacket;
-
- // Process packet data.
- pDCLCommand = *ppDCLCommand;
- packetSizeLeft = packetSize;
- waitForPacket = false;
- while ((pDCLCommand != nil) && (!waitForPacket))
- {
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLReceivePacketStartOp :
- if (packetSize > 0)
- {
- LynxFWIMDCLReceivePacketStart
- (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
- }
- else
- {
- waitForPacket = true;
- }
- break;
-
- case kDCLReceiveBufferOp :
- packetBuffer += sizeof (UInt32); // Skip header//zzz not quite right.
- LynxFWIMDCLReceiveBuffer
- (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
- break;
-
- case kDCLCallProcOp :
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- break;
-
- case kDCLJumpOp :
- pDCLJump = (DCLJumpPtr) pDCLCommand;
- pDCLCommand = (DCLCommandPtr) pDCLJump->pJumpDCLLabel;
- break;
-
- default :
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- break;
- }
- }
-
- // Update current DCL command.
- *ppDCLCommand = pDCLCommand;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDCLReceivePacketStart
- //
- // This proc processes a DCL receive packet command.
- // This is obsolete, but shows how one could manually process DCLs.
- //
-
- static void LynxFWIMDCLReceivePacketStart(
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- UInt32 packetSize;
- UInt32 dclPacketSize;
- UInt32 transferSize;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) *ppDCLCommand;
-
- // Compute transfer size.
- dclPacketSize = pDCLTransferPacket->size;
- packetSize = *pPacketSize + sizeof (UInt32);//zzz include header
- if (dclPacketSize > packetSize)
- transferSize = packetSize;
- else
- transferSize = dclPacketSize;
-
- // Transfer the packet data.
- if (transferSize > 0)
- BlockCopy (*pPacketBuffer, pDCLTransferPacket->buffer, transferSize);
-
- // We're done with DCL and packet.
- *ppDCLCommand = pDCLTransferPacket->pNextDCLCommand;
- *pPacketSize = 0;
- *pWaitForPacket = false;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDCLReceiveBuffer
- //
- // This proc processes a DCL receive buffer command.
- // This is obsolete, but shows how one could manually process DCLs.
- //
-
- static void LynxFWIMDCLReceiveBuffer(
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket)
- {
- DCLTransferBufferPtr pDCLTransferBuffer;
- UInt32 bufferSizeLeft;
- UInt32 packetSize;
- UInt32 transferSize;
-
- // Recast DCL command.
- pDCLTransferBuffer = (DCLTransferBufferPtr) *ppDCLCommand;
-
- // Compute transfer size.
- bufferSizeLeft = pDCLTransferBuffer->size - pDCLTransferBuffer->bufferOffset;
- packetSize = *pPacketSize;
- if (bufferSizeLeft > packetSize)
- transferSize = packetSize;
- else
- transferSize = bufferSizeLeft;
-
- // Transfer the packet data.
- if (transferSize > 0)
- {
- BlockCopy (*pPacketBuffer,
- pDCLTransferBuffer->buffer + pDCLTransferBuffer->bufferOffset,
- transferSize);
-
- *pPacketBuffer += transferSize;
- *pPacketSize -= transferSize;
- pDCLTransferBuffer->bufferOffset += transferSize;
- }
-
- // Check if we're done with this DCL or need another packet.
- if (pDCLTransferBuffer->bufferOffset == pDCLTransferBuffer->size)
- {
- *ppDCLCommand = pDCLTransferBuffer->pNextDCLCommand;
- *pWaitForPacket = false;
- }
- else
- {
- *pWaitForPacket = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAllocateIsochPort
- //
- // This routine will allocate an isochronous channel.
- //zzz must make sure that port is not already in use.
- //zzz should do more error checking.
- //zzz we may need to keep a list of isoch port data records.
- //
-
- static OSStatus LynxFWIMAllocateIsochPort(
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxIsochPortDataPtr pLynxIsochPortData = nil;
- LynxRegistersPtr pLynxRegs;
- SInt32 dmaChannelNum;
- UInt32 isochChannelNum;
- Boolean talking;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMAllocateIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAllocateIsochPortParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get base address of Lynx registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Are we talking?
- talking = pFWIMAllocateIsochPortParams->talking;
-
- // find a free dma channel.
- dmaChannelNum = LynxAllocateDMAChannel( pLynxFWIMData );
-
- if (talking)
- pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kIsochXmit;
- else
- pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kIsochRcv;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- // if dma channel is not in use
- if ( !status && dmaChannelNum >= 0 && pLynxFWIMData->lynxIsochPortDataList[dmaChannelNum] == nil)
- {
-
- // Create an isoch port data record.
- pLynxIsochPortData =
- (LynxIsochPortDataPtr) PoolAllocateResident (sizeof (LynxIsochPortData), true);
- if (pLynxIsochPortData != nil)
- {
- pLynxFWIMData->lynxIsochPortDataList[dmaChannelNum] = pLynxIsochPortData;
- pLynxIsochPortData->originalDCLProgramID =
- pFWIMAllocateIsochPortParams->dclProgramID;
- pLynxIsochPortData->translatedDCLProgramID = kInvalidDCLProgramID;
- pLynxIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
- pLynxIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
- pLynxIsochPortData->talking = talking;
- pLynxIsochPortData->dmaChannel = dmaChannelNum;
- // Enable appropriate Interrupts
- LynxFWIMInterruptSetup( pLynxFWIMData );
- }
- else
- {
- status = memFullErr;
- }
-
- // Compile a PCL program from DCL program.
- if (status == noErr)
- {
- // Check if DCL program must be translated.
- if (LynxFWIMIsCompilableDCLProgram (pLynxIsochPortData->originalDCLProgramID))
- {
- pLynxIsochPortData->dclProgramID = pLynxIsochPortData->originalDCLProgramID;
- pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram = pLynxIsochPortData->dclProgramID;
- }
- else
- {
- //zzz need to be able to deallocate this.
- status = FWTranslateDCLProgram (pLynxIsochPortData->originalDCLProgramID,
- &(pLynxIsochPortData->translatedDCLProgramID));
- if (status == noErr)
- {
- pLynxIsochPortData->dclProgramID =
- pLynxIsochPortData->translatedDCLProgramID;
- pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram = pLynxIsochPortData->dclProgramID;
- }
- }
-
- // Compile the DCL program.
- if (status == noErr)
- {
- status = LynxFWIMCompileDCLProgram
- (pLynxFWIMData,
- pLynxIsochPortData->dclProgramID,
- dmaChannelNum,
- pLynxIsochPortData->channelNum,
- pLynxIsochPortData->speed);
- }
-
- // Set start, stop, and release procedures for DCL program.
- if (status == noErr)
- {
- if (talking)
- {
- FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMStartTalkingDCLProgram);
- FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMStopTalkingDCLProgram);
- FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMReleaseDCLProgram);
- }
- else
- {
- FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMStartListeningDCLProgram);
- FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMStopListeningDCLProgram);
- FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
- LynxFWIMReleaseDCLProgram);
- }
- }
- }
-
- // Set up appropriate DMA channel.
- if (status == noErr)
- {
- // Quiet the DMA channel.
- pLynxRegs->dmaChannel[dmaChannelNum].control = EndianSwapImm32Bit (0);
- SynchronizeIO ();
-
- // Switch to isochronous transmit mode if we're talking.
- if (talking)
- {
- IncrementAtomic( &pLynxFWIMData->isochTransmitMode);
- LynxFWIMSetupFIFOs (pLynxFWIMData);
- }
-
- // Set up comparators to receive on this port's channel.
- if (!talking)
- {
- isochChannelNum = pLynxIsochPortData->channelNum;
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].value0,
- (UInt32)EndianSwapImm32Bit (isochChannelNum << kLynxCMP0_FIELD2_MASKPhase));
-
- if( !status ) {
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask0,
- (UInt32)EndianSwapImm32Bit ((kLynxIsotCodeNormal << kLynxCMP0_FIELD3_MASKPhase) |
- (kLynxMatchIsochChannel << kLynxCMP0_FIELD2_MASKPhase)));
- }
- SynchronizeIO ();
- }
-
- // Set our data for port.
- pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData =
- (UInt32) pLynxIsochPortData;
- }
-
- // Clean up on error.
- if (status != noErr)
- {
- if (pLynxIsochPortData != nil)
- _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
- }
- }
- else
- {
- // dma channel is in use
- status = paramErr; // better error?
- }
-
- // Complete FWIM command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReleaseIsochPort
- //
- // This routine will release resources allocated for the given isochronous
- // channel.
- //
-
- static OSStatus LynxFWIMReleaseIsochPort(
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxIsochPortDataPtr pLynxIsochPortData;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMReleaseIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMReleaseIsochPortParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pLynxIsochPortData = (LynxIsochPortDataPtr)
- pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Release resources for isoch port.
- if (pLynxIsochPortData != nil)
- status = _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
-
- // Complete FWIM command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // _LynxFWIMReleaseIsochPort
- //
- // This routine will release resources allocated for the given isochronous
- // channel.
- //
-
- static OSStatus _LynxFWIMReleaseIsochPort(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxIsochPortDataPtr pLynxIsochPortData)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData = nil;
- OSStatus status = noErr;
-
- // Clear isoch port data from fwim list
- if (pLynxFWIMData->lynxIsochPortDataList[pLynxIsochPortData->dmaChannel] == pLynxIsochPortData)
- pLynxFWIMData->lynxIsochPortDataList[pLynxIsochPortData->dmaChannel] = nil;
-
- // Give back the DMA channel and setup the interrupts correctly again
- LynxDeAllocateDMAChannel( pLynxFWIMData, pLynxIsochPortData->dmaChannel );
-
- // If we're releasing a talking port, switch out of isoch transmit mode.
- if (pLynxIsochPortData->talking)
- {
- // Switch out of isochronous transmit mode.
- DecrementAtomic( &pLynxFWIMData->isochTransmitMode);
- LynxFWIMSetupFIFOs (pLynxFWIMData);
- }
-
- // Release DCL resources.
- if (pLynxIsochPortData->originalDCLProgramID != kInvalidDCLProgramID)
- status = FWReleaseDCLProgram (pLynxIsochPortData->originalDCLProgramID);
-
- // Deallocate isoch port data record.
- PoolDeallocate ((Ptr) pLynxIsochPortData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartIsochPort
- //
- // Start up the given isochronous port on the given sync event using the
- // given buffer.
- //
-
- static OSStatus LynxFWIMStartIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxIsochPortDataPtr pLynxIsochPortData;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMStartIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pLynxIsochPortData = (LynxIsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- if( pLynxFWIMData->phyNotPowered )
- status = accessErr; // !!! Proper error?
-
- // Start DCL program.
- if (status == noErr)
- status = FWStartDCLProgram (pLynxIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStopIsochPort
- //
- // Stop the given isochronous port on the given sync event.
- //
-
- static OSStatus LynxFWIMStopIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxIsochPortDataPtr pLynxIsochPortData;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMStopIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Set pending command.
- pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
-
- // Get isoch port data.
- pLynxIsochPortData = (LynxIsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Stop DCL program.
- if (status == noErr)
- status = FWStopDCLProgram (pLynxIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartTalkingDCLProgram
- //
- // This routine starts running the given DCL program.
- //
-
- static OSStatus LynxFWIMStartTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
- UInt32 dmaChannelNum;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
- if (status == noErr)
- pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
-
- // Get base address of Lynx registers.
- if (status == noErr)
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // Figure out what DMA channel is used by this DCL
- dmaChannelNum = 0;
- while( dmaChannelNum < kNumDMAChannels ) {
- if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
- break;
- dmaChannelNum++;
- }
-
- SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
- if( dmaChannelNum < kNumDMAChannels ) {
- // We'll report statistics at the end of the transmit, if FireBug enabled.
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoOverUnderErrorCounters,
- (UInt32) EndianSwapImm32Bit (0) );
-
- if( !status ) {
- // Load a physical address
- pLynxRegs->dmaChannel[dmaChannelNum].curPCLAddr =
- EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
- SynchronizeIO ();
-
- // Set CH ENA and Link bits to enable DMA.
- pLynxRegs->dmaChannel[dmaChannelNum].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO ();
-
- // In rare cases, we might not start transmitting. Somehow the FIFO gets jammed,
- // even though we flush it before and after iso transmit programs run. I have
- // only seen this in pre-revA parts, so maybe it's one of the errata items.
- }
- }
- else
- status = channelNotAvailableErr; // Should never happen, I think.
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStartListeningDCLProgram
- //
- // This routine starts running the given DCL program.
- //
-
- static OSStatus LynxFWIMStartListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
- UInt32 dmaChannelNum;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
- if (status == noErr)
- pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
-
- // Get base address of Lynx registers.
- if (status == noErr)
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // Figure out what DMA channel is used by this DCL
- dmaChannelNum = 0;
- while( dmaChannelNum < kNumDMAChannels ) {
- if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
- break;
- dmaChannelNum++;
- }
-
- SynchronizeIO();// • Damn Compiler Bug!
- if( dmaChannelNum < kNumDMAChannels ) {
-
- // Load a physical address
- pLynxRegs->dmaChannel[dmaChannelNum].curPCLAddr =
- EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
- SynchronizeIO ();
-
- // Set ready, CH ENA, and Link bits to enable DMA.
- pLynxRegs->dmaChannel[dmaChannelNum].ready =
- EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
- SynchronizeIO ();
-
- pLynxRegs->dmaChannel[dmaChannelNum].control =
- EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO ();
-
- // Enable receive comparator.
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask1,
- (UInt32)EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
- SynchronizeIO ();
- }
- else
- status = channelNotAvailableErr; // Should never happen, I think.
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStopTalkingDCLProgram
- //
- // This routine stops running the given DCL program.
- //
-
- static OSStatus LynxFWIMStopTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- #ifdef DMA_FLUSH_CODE
- #if DMA_FLUSH_CODE
- UInt32 linkFIFO, pciFIFO, waitForFIFO;
- UInt32 linkFIFO1, pciFIFO1;
- #endif
- #endif
- OSStatus status = noErr;
- UInt32 dmaChannelNum;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
-
- if (status == noErr)
- pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
-
- // Get base address of Lynx registers.
- if (status == noErr)
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Figure out what DMA channel is used by this DCL
- dmaChannelNum = 0;
- while( dmaChannelNum < kNumDMAChannels ) {
- if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
- break;
- dmaChannelNum++;
- }
-
- SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
- if( dmaChannelNum < kNumDMAChannels ) {
-
- // Removed unnecessary pre-REV A code to deal with PHY JAMs
- //zzz Read quad out of ITF FIFO to clear underflow jams.
- //pLynxFWIMData->bitBucket = pLynxRegs->itfPopPush0;
-
- // Clear the Ready bit. Each transmit PCL has a wait-for-ready,
- // so the DMA will pause before the start of the next packet.
- pLynxRegs->dmaChannel[dmaChannelNum].ready = EndianSwapImm32Bit (0);
- SynchronizeIO ();
-
- // In very unusual circumstances, it could be a long time until the DMA
- // stops. For example, we could have preloaded 30 or 40 cycles of tiny
- // packets (say, header only with zero payload) and now we're trying to
- // send one really big packet (larger than the FIFO). Because the IT DMA
- // tries to work ahead, it will be loading that big packet a little at a
- // time, as room becomes available in the FIFO. That could take 30 or 40
- // cycles before the DMA finishes the current command and can pause.
-
- // To be sure the pause really took effect, wait here until the IT FIFO
- // is empty. If the FIFO is full because we can't transmit, this would
- // wait forever, so also bail out if we wait too long.
- // zzz should use real time, not one million loops.
-
- // A better way to do this would be to arrange for an interrupt.
- // But that's complicated - one would have to rewrite part of the
- // PCL to interrupt and halt, then resume it, then exit here, then
- // take the interrupt, then clean up the PCL (which might be reused later).
-
- // For now we will just wait 2ms. This way we don't have to access registers
- // which might not be safe if the PHY is unpowered or missing. This is
- // not completly sufficient for the pathological case described above but
- // will work fine for DV and all known existing clients.
-
- #ifdef DMA_FLUSH_CODE
- #if DMA_FLUSH_CODE
- waitForFIFO = 1000000;
- while (waitForFIFO && !status )
- {
- waitForFIFO--;
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->pciFifoPort, // !!! original code used linkFifoPort! Was this a bug? Seems like it
- (UInt32 *) &pciFIFO);
-
- // DMA can't access the linkFifoPort register without hosing the Link chip! For now use
- // the processor on the theory that we just successfully got pciFifoPort data without
- // a problem and that it should still be OK. Long term we want to find a better way to
- // do this.
- if( !status ) {
- // status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- // (UInt32 *) &pLynxRegs->linkFifoPort,
- // (UInt32 *) &linkFIFO);
-
- linkFIFO = pLynxRegs->linkFifoPort;
-
- }
-
- linkFIFO = EndianSwap32Bit (linkFIFO);
- pciFIFO = EndianSwap32Bit (pciFIFO);
-
- // The mask checks both the FIFO index and the "wrap-around" bit.
- // They both have to be equal if the FIFO is empty. If they are
- // equal, make sure they are also unchanged. If either of them
- // "moved", try again.
-
- if ((linkFIFO && 0x04ff0000) == (pciFIFO && 0x04ff0000))
- {
-
- if( !status ) {
-
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->pciFifoPort, // !!! original code used linkFifoPort! Was this a bug? Seems like it
- (UInt32 *) &pciFIFO1);
- }
-
- // DMA can't access the linkFifoPort register without hosing the Link chip! For now use
- // the processor on the theory that we just successfully got pciFifoPort data without
- // a problem and that it should still be OK. Long term we want to find a better way to
- // do this.
- if( !status ) {
- // status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- // (UInt32 *) &pLynxRegs->linkFifoPort,
- // (UInt32 *) &linkFIFO1);
-
- linkFIFO1 = pLynxRegs->linkFifoPort;
-
- }
-
- if ((linkFIFO == EndianSwap32Bit (linkFIFO1)) &&
- (pciFIFO == EndianSwap32Bit (pciFIFO1)))
- waitForFIFO = 0;
- }
- }
- #else
- // Just wait a while rather than poking on registers which might crash the
- // machine. See comment block above.
- DelayForHardware(DurationToAbsolute(durationMillisecond * 2));
- #endif
- #endif
-
- // DMA must be idle by now, so it's safe to turn it off.
- pLynxRegs->dmaChannel[dmaChannelNum].control &=
- ~EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
- SynchronizeIO ();
-
- #ifdef LynxFireBug
- {
- UInt32 temp;
-
- if( !status ) {
- status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoOverUnderErrorCounters,
- (UInt32 *) &temp );
- temp = EndianSwap32Bit (temp );
-
- sprintf (fireBug, "LynxFWIM: FIFO stats during iso tx: ITF_UNDER %ld, ATF_UNDER %ld, GRF_OVER %ld",
- (temp >> 16) & 0xff, (temp >> 8) & 0xff, temp & 0xff);
- LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
- }
- }
- #endif
- }
- else
- status = channelNotAvailableErr; // Should never happen, I think.
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMStopListeningDCLProgram
- //
- // This routine stops running the given DCL program.
- //
-
- static OSStatus LynxFWIMStopListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- OSStatus status = noErr;
- UInt32 dmaChannelNum;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
- if (status == noErr)
- pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
-
- // Get base address of Lynx registers.
- if (status == noErr)
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Figure out what DMA channel is used by this DCL
- dmaChannelNum = 0;
- while( dmaChannelNum < kNumDMAChannels ) {
- if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
- break;
- dmaChannelNum++;
- }
-
- SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
- if( dmaChannelNum < kNumDMAChannels ) {
- // Disable channel comparator.
- //zzz need way to bit bucket any remaining packets in FIFO
- status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask1,
- (UInt32) 0);
- SynchronizeIO ();
- }
- else
- status = channelNotAvailableErr; // Should never happen, I think.
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReleaseDCLProgram
- //
- // This routine releases the resources allocated for the given DCL program.
- //
-
- static OSStatus LynxFWIMReleaseDCLProgram(
- DCLProgramID dclProgramID)
- {
- LynxDCLCompilerEngineDataPtr
- pLynxDCLCompilerEngineData;
- LynxFWIMDataPtr pLynxFWIMData;
- OSStatus status = noErr;
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
- if (status == noErr)
- pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
-
- if (status == noErr)
- {
- // Deallocate PCL pools.
- if (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList != nil)
- {
- LynxFWIMDeallocatePCLPools
- (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList);
- }
-
- // Release all VM resources
- // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
- if (pLynxDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
- {
- status = CheckpointIO (pLynxDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
- if (status != noErr)
- {
- sprintf (debugStr, "DCL data CheckpointIO status %ld",
- (long) status);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
- PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.physicalMapping);
- }
-
- // Deallocate engine data.
- PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMReadRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //
-
- static OSStatus LynxFWIMReadRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- LynxFWIMDataPtr pLynxFWIMData;
- UInt32 commandAcceptance;
- Boolean commandBusy;
- UInt32 ackCode, ackType;
- LynxPCLPtr pPCL;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
-
- // Note that timer went off.
- pLynxFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Retry if there are more retries left, otherwise return with timeout
- // status.
- if (commandBusy)
- {
-
- // Check to see if the read request was actually received by somebody.
- // If nobody was home only do one retry.
- // !!! This assumes that we have only the one AsyncTXPCL AND that nobody
- // has used it since then. Since this FWIM is pretty single threaded this is
- // safe for now.
- pPCL = &pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL];
- ackCode = (EndianSwap32Bit (pPCL->status) & kLynxAcks) >> kLynxAcksPhase;
- ackType = ((EndianSwap32Bit (pPCL->status) & kLynxAck_Type) != 0);
- if (ackType != 0 && ackCode == 1) { // Special ack 1 (Link Timeout)
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 2)
- pFWIMAsynchCommandParams->numRetries = 2;
- }
-
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = LynxFWIMRead (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWriteRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //zzz Only need this until reset code completes commands manually.
- //zzz need locking mechanism between this routine and the ack int routine.
- //
- // Note - presently unused (not set in LynxFWIMWrite)
-
- static OSStatus LynxFWIMWriteRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- LynxFWIMDataPtr pLynxFWIMData;
- LynxRegistersPtr pLynxRegs;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Note that timer went off.
- pLynxFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Check if ack code indicates a completed transfer. Retry if it doesn't.
- if (commandBusy)
- {
- // NYI
- // Works differently in Lynx - look in DMA/PCL status
- FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler - NYI ###");
- #if 0
- nodeAddress = EndianSwap32Bit (pLinkRegs->nodeAddress);
- ackCode =
- (nodeAddress & kTINodeAddressATAck) >> kTINodeAddressATAckPhase;
- if (ackCode == kFWAckComplete)
- {
- commandBusy = false;
- status = noErr;
- }
- else
- {
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = LynxFWIMWrite (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
- #endif
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMLockRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //zzz need to check if command is still busy.
- // NYI - Never tested for Lynx
- //
-
- static OSStatus LynxFWIMLockRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- LynxFWIMDataPtr pLynxFWIMData;
- UInt32 commandAcceptance;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMLockRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
-
- // Note that timer went off.
- pLynxFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Retry if there are more retries left, otherwise return with timeout
- // status.
- if (commandBusy)
- {
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = LynxFWIMLock (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return (status);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDeferredTaskMultiplexer
- //
- // Dispatches the deferred task to the appropriate routine based on
- // DMAInfo.channelType
- //
-
- static void LynxFWIMDeferredTaskMultiplexer(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 dmaChannel = (UInt32) p2;
-
- pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled = false;
-
- switch( pLynxFWIMData->DMAInfo[dmaChannel].channelType ) {
-
- case kChannelUnused:
- break;
- case kAsyncRcv:
- LynxFWIMDMAAsyncPCLDeferredTask( p1, p2);
- break;
- case kIsochXmit:
- LynxFWIMDMAIsochTransmitDeferredTask( p1, p2);
- break;
- case kIsochRcv:
- LynxFWIMDMAIsochReceivePCLDeferredTask( p1, p2);
- break;
-
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDMAAsyncPCLDeferredTask
- //
- // Dispatches self-ID and async packets after DMA is finished
- //
-
- static void LynxFWIMDMAAsyncPCLDeferredTask(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- LynxPCLPtr pPCL, pSkimPCL, pLastSelfIDsPCL;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData, pSkimPCLData;
- UInt32 pclStatus, skimStatus;
- UInt32 packetSize, skimSize;
- Ptr packetBuffer;
- UInt32 quad0, quad1;
- Boolean skimDone;
- UInt32 skipCount;
- static UInt32 skipTotal = 0;
- OSStatus status = noErr;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // This is part of a temporary hack.
- // Within 50ms after a bus reset, don't accept any packets.
- // We'll get called again after these flags are cleared.
-
- if ((pLynxFWIMData->delayedResetTimerSet) || (pLynxFWIMData->busResetDTScheduled)) {
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
- return;
- }
-
- // Get next PCL to process and its data.
- pPCL = pLynxFWIMData->pNextAsyncPCL;
- if (pPCL != nil)
- {
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pclStatus = EndianSwap32Bit (pPCL->status);
- }
- else
- {
- pclStatus = kLynxInvalidStatus;
- }
-
- pLynxFWIMData->selfIDPackets = 0; // Make sure this is zero coming in.
-
- // Process all PCLs with data.
- while (pclStatus & kLynxPktCmp)
- {
- // Set next PCL to process.
- pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
-
- // If this packet is self-IDs, and we are running behind, then
- // there could be *another* packet with self-IDs waiting too.
- // In that case, we can avoid a bunch of PHY register reads
- // and other work by just skipping to the last available self-IDs.
- // The skipped packets can't contain any responses we want, and
- // we will be unable to reply to any requests during that period,
- // so we can safely dispose of all of the packets.
-
- // In theory it is possible for someone to have sent us a write
- // request to which we sent ack_complete. However, because this
- // write request was sent after a bus reset, and before we had ever
- // identified ourselves, the sender has no way to know who we are.
- // So we can safely ignore such a request even if we said ack_complete.
-
- // zzz However, if someone sent a *broadcast* write, they might reasonably
- // except us to (try to) receive it. If we find a broadcast write while
- // scanning ahead, we really ought to stop scanning at that point.
-
- // Process packet if it had no errors. Otherwise recycle PCL.
- if (!(pclStatus & (kLynxMstErr | kLynxPktErr)))
- {
-
- // Get packet buffer and length.
- packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
- packetSize = (pclStatus & kLynxTransferredCount) >>
- kLynxTransferredCountPhase;
-
- // Get first two quads.
- quad0 = ((UInt32 *) packetBuffer)[0];
- quad1 = ((UInt32 *) packetBuffer)[1];
-
- // If length is zero or first quad is inverse of second quad, assume self-IDs
- if ((packetSize == 0) || (quad0 == ~quad1))
- {
- // Self-IDs
- do { // while (pLynxFWIMData->selfIDPackets)
-
- pLastSelfIDsPCL = pSkimPCL = pPCL;
- pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
- skimStatus = EndianSwap32Bit (pPCL->status);
- skimDone = false;
-
- while (skimDone == false)
- {
- // Move to next PCL
- pSkimPCL = pSkimPCLData->pNextPCL;
- if (pSkimPCL == nil)
- {
- // Hit the end of the list
- skimDone = true;
- }
- else
- {
- pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
- skimStatus = EndianSwap32Bit (pSkimPCL->status);
- }
-
- if ((skimDone == false) && (skimStatus & kLynxPktCmp))
- {
- // pSkimPCL points to a PCL that has been executed
- // If this one had an error, just keep looking.
- if (!(skimStatus & (kLynxMstErr | kLynxPktErr)))
- {
- // Get packet buffer and length.
- skimSize = (skimStatus & kLynxTransferredCount) >>
- kLynxTransferredCountPhase;
-
- // Get first two quads.
- quad0 = ((UInt32 *) pSkimPCLData->packetBuffer)[0];
- quad1 = ((UInt32 *) pSkimPCLData->packetBuffer)[1];
-
- // If length is zero or first quad is inverse of second quad, assume self-IDs
- if ((skimSize == 0) || (quad0 == ~quad1))
- {
- // This is the latest point we can skip ahead to (so far)
- pLastSelfIDsPCL = pSkimPCL;
- }
- }
- }
- else // ran out of places to look
- {
- skimDone = true;
- }
- }
-
- if (pLastSelfIDsPCL != pPCL)
- {
- // recycle skipped PCLs and
- // set up for alternate
-
- skipCount = 0;
- while (pPCL != pLastSelfIDsPCL)
- {
- // Add PCL back to active list.
- pSkimPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pSkimPCL = pSkimPCLData->pNextPCL;
- LynxFWIMAddAsyncRxPCL (pPCL);
- pPCL = pSkimPCL;
- skipCount++;
- skipTotal++;
- }
-
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
- pclStatus = EndianSwap32Bit (pPCL->status);
- packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
- packetSize = (pclStatus & kLynxTransferredCount) >>
- kLynxTransferredCountPhase;
-
- //sprintf (fireBug, "LynxFWIM: Skipped %ld useless packets [%ld total]",
- // (long) skipCount, (long) skipTotal);
- //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
- }
-
- // If we had previously found some self-ID packets then this is the second time
- // through here after finding self-IDs. If pPCL still points at what we had
- // the last time then no more self-IDs have come in and its safe to tell the
- // FSL about our new node ID and bus topology. If pPCL points to something
- // different then new self-IDs have come in and since we asked the PHY what
- // our node-ID is and we may be out of sync. In this case we start again by
- // processing the packet and looping.
-
- if( pLynxFWIMData->selfIDPackets && pLynxFWIMData->selfIDPackets == pPCL ) {
- LynxFWIMInformFSLofSelfIDs( pLynxFWIMData ); // Also recycles PCL
- pLynxFWIMData->selfIDPackets = 0;
- }
- else {
- // First time through or we got new selfIDs after processing the packet
- if( pLynxFWIMData->selfIDPackets )
- LynxFWIMAddAsyncRxPCL (pLynxFWIMData->selfIDPackets);
- pLynxFWIMData->selfIDPackets = pPCL;
- pLynxFWIMData->selfIDPacketBuffer = packetBuffer;
- pLynxFWIMData->selfIDPacketSize = packetSize;
-
- // We have self-ids, so lets go stuff the globals with what the PHY thinks is our
- // local node ID and filter out/create our self-ID packet.
- LynxFWIMProcessPacket (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- }
- } while ( pLynxFWIMData->selfIDPackets );
- }
- else {
- // Process packet if not self-ID.
- LynxFWIMProcessPacket (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- }
- }
- else
- {
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
- // Process next PCL.
- pPCL = pLynxFWIMData->pNextAsyncPCL;
- if (pPCL != nil)
- {
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
- pclStatus = EndianSwap32Bit (pPCL->status);
- }
- else
- {
- pclStatus = kLynxInvalidStatus;
- }
- }
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMInformFSLofSelfIDs
- //
- // Calls FWProcessSelfIDs
- //
-
- static void LynxFWIMInformFSLofSelfIDs(
- LynxFWIMDataPtr pLynxFWIMData )
- {
-
- FWIMProcessSelfIDsParams fwimProcessSelfIDsParams;
-
- // Process the self IDs.
- //zzz need to get status.
- fwimProcessSelfIDsParams.fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- fwimProcessSelfIDsParams.pSelfIDList = (Ptr) pLynxFWIMData->selfIDPacketBuffer;
- fwimProcessSelfIDsParams.selfIDListSize = pLynxFWIMData->selfIDPacketSize;
- fwimProcessSelfIDsParams.pLocalSelfID = (Ptr) pLynxFWIMData->localSelfIDQuads;
-
- if( pLynxFWIMData->numPHYPorts > 3 )
- fwimProcessSelfIDsParams.localSelfIDSize = 8 * (((pLynxFWIMData->numPHYPorts - 4) >> 3) + 2);
- else
- fwimProcessSelfIDsParams.localSelfIDSize = 8;
-
- fwimProcessSelfIDsParams.processSelfIDsFlags = 0;
- FWProcessSelfIDs (&fwimProcessSelfIDsParams);
-
- pLynxFWIMData->generation = fwimProcessSelfIDsParams.generation;
- pLynxFWIMData->generationValid = true;
-
- // We used to load the nodeID register here, but this was a bad place to
- // do it. That's now done based on PHY register receive interrupts.
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pLynxFWIMData->selfIDPackets);
-
- pLynxFWIMData->selfIDPackets = 0;
-
-
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDMAIsochReceivePCLDeferredTask
- //
- // Handles PCL interrupts for isochronous receive.
- //
-
- static void LynxFWIMDMAIsochReceivePCLDeferredTask(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 dmaChannel = (UInt32) p2;
- LynxIsochPortDataPtr pLynxIsochPortData;
- static LynxDCLProgramInterruptQueueElementPtr
- pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
- LynxDCLProgramInterruptQueueElementPtr
- pDCLInterrupt,
- pDCLFirstInterrupt,
- pPrevDCLInterrupt;
- DCLCommandPtr pDCLCommand;
- DCLCallProcPtr pDCLCallProc;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 numInterrupts;
- OSStatus status = noErr;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Get isoch port data.
- pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[dmaChannel];
-
- // Get and clear interrupt queue tail.
- pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
- while (!CompareAndSwap
- ((UInt32) pDCLInterrupt,
- nil,
- (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[dmaChannel])))
- {
- pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
- }
-
- // remember for later
- pDCLFirstInterrupt = pDCLInterrupt;
-
- // Build interrupt list and clear interrupts.
- numInterrupts = 0;
- while ((pDCLInterrupt != nil) && (numInterrupts < 10))
- {
- pDCLInterruptList[numInterrupts] = pDCLInterrupt;
- pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
- pDCLInterrupt->pPrevDCLInterrupt = nil;
- numInterrupts++;
-
- pDCLInterrupt = pPrevDCLInterrupt;
- }
-
- /////////////////////////////////
- // There is an occasional case where the list of DCLs to be serviced can become slightly corrupt.
- // The case is:
- // the DMA reads the value from the tail register
- // the defered task sets the tail to nil
- // the DMA sets the tail to the current DCL to be serviced
- // This causes the newest DCL serviced during one deferred task to be the last DCL serviced during
- // the next deferred task. Instead of preventing this case. We just look for its results and undo
- // them.
-
- if( ( numInterrupts > 1)
- && ( pDCLInterruptList[numInterrupts - 1] == pLynxFWIMData->pDCLLastInterrupt[dmaChannel] ) )
- numInterrupts--;
-
- // save for corruption case
- pLynxFWIMData->pDCLLastInterrupt[dmaChannel] = pDCLFirstInterrupt;
-
- /////////////////////////////////
-
- // Run through interrupt queue.
- while (numInterrupts--)
- {
- // Get DCL command that caused interrupt.
- pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
- }
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMDMAIsochTransmitDeferredTask
- //
- // Handles PCL interrupts for isochronous transmit.
- //
-
- static void LynxFWIMDMAIsochTransmitDeferredTask(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 dmaChannel = (UInt32) p2;
- LynxIsochPortDataPtr pLynxIsochPortData;
- static LynxDCLProgramInterruptQueueElementPtr
- pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
- LynxDCLProgramInterruptQueueElementPtr
- pDCLInterrupt,
- pDCLFirstInterrupt,
- pPrevDCLInterrupt;
- DCLCommandPtr pDCLCommand;
- DCLCallProcPtr pDCLCallProc;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 numInterrupts;
- OSStatus status = noErr;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Get isoch port data.
- pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[dmaChannel];
-
- // Get and clear interrupt queue tail.
- pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
- while (!CompareAndSwap
- ((UInt32) pDCLInterrupt,
- nil,
- (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[dmaChannel])))
- {
- pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
- }
-
- // remember for later
- pDCLFirstInterrupt = pDCLInterrupt;
-
- // Build interrupt list and clear interrupts.
- numInterrupts = 0;
- while ((pDCLInterrupt != nil) && (numInterrupts < 10))
- {
- pDCLInterruptList[numInterrupts] = pDCLInterrupt;
- pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
- pDCLInterrupt->pPrevDCLInterrupt = nil;
- numInterrupts++;
-
- pDCLInterrupt = pPrevDCLInterrupt;
- }
-
- /////////////////////////////////
- // There is an occasional case where the list of DCLs to be serviced can become slightly corrupt.
- // The case is:
- // the DMA reads the value from the tail register
- // the defered task sets the tail to nil
- // the DMA sets the tail to the current DCL to be serviced
- // This causes the newest DCL serviced during one deferred task to be the last DCL serviced during
- // the next deferred task. Instead of preventing this case. We just look for its results and undo
- // them.
-
- if( ( numInterrupts > 1)
- && ( pDCLInterruptList[numInterrupts - 1] == pLynxFWIMData->pDCLLastInterrupt[dmaChannel] ) )
- numInterrupts--;
-
- // save for corruption case
- pLynxFWIMData->pDCLLastInterrupt[dmaChannel] = pDCLFirstInterrupt;
-
- /////////////////////////////////
-
- // Run through interrupt queue.
- while (numInterrupts--)
- {
- // Get DCL command that caused interrupt.
- pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMResetDeferredTask
- //
- // This proc deals with bus resets at FireWire deferred task time.
- //
-
- static void LynxFWIMResetDeferredTask(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMResetDeferredTask");
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // Bus reset DT no longer scheduled.
- pLynxFWIMData->busResetDTScheduled = false;
-
- // This is a temporary hack. We want to reduce the risk of PHY jams.
- // So after a bus reset, before we process the self-IDs, wait 50ms to
- // allow another bus reset (if any) to arrive. When this timer goes
- // off, if busResetDTScheduled has become true again, then there was
- // another bus reset. By the time we get to the self-IDs for the first
- // reset, we'll be able to skip forward over them and avoid some PHY
- // register accesses.
-
- // If there are more resets beyond 50ms, we won't keep waiting - otherwise
- // we might hang if there were endless resets. But hopefully we will have
- // managed to skip some of them.
-
- if (pLynxFWIMData->delayedResetTimerSet == false)
- {
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (50 * durationMillisecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMDelayedReset,
- pLynxFWIMData,
- &(pLynxFWIMData->delayedResetTimerID));
- if (status == noErr)
- pLynxFWIMData->delayedResetTimerSet = true;
- else LynxFWIMDelayedReset (p1, nil); // Might as well proceed (should never happen)
- }
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
-
- }
-
-
- static OSStatus LynxFWIMDelayedReset(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- LynxRegistersPtr pLynxRegs;
-
- pLynxFWIMData->delayedResetTimerSet = false;
-
- // Get base address of Lynx registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // Re-enable data transmission.
- LynxFWIMSetLinkControlBits
- (pLynxFWIMData,
- EndianSwapImm32Bit( kLynxTX_ASYNC_EN ));
-
- // If there's a pending FWIM command, set its status to busReconfiguredErr.
- //zzz should we do this here, or in services?
- //zzz this probably should not be done on all types of commands.
- if (pLynxFWIMData->pPendingFWIMCommand)
- {
- if (pLynxFWIMData->pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
- pLynxFWIMData->pendingFWIMCommandStatus = busReconfiguredErr;
- }
-
- // During the period that delayedResetTimerSet was true,
- // no async packets were processed.
- // Now (another hack) process any that are waiting:
-
- LynxFWIMHandleDMAInterrupt (pLynxFWIMData, pLynxFWIMData->asyncRxDMA);
-
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMHoldoffResetRequests
- //
- // This proc handles bus reset holdoff timer expiring. Check if any bus reset
- // requests are pending and complete them.
- //
-
- static OSStatus LynxFWIMHoldoffResetRequests(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 commandAcceptance;
- UInt32 i;
- OSStatus status = noErr;
-
- // turn off timer set flag
- pLynxFWIMData->holdoffResetRequestsTimerSet = false;
-
- // if a bus reset request came in during the timer period, issue the request request
- for (i=0;i<kPendingResetRequestsAllowed;i++)
- {
- if (pLynxFWIMData->pResetRequestList[i].inUse)
- {
- status = LynxFWIMResetBus(pLynxFWIMData->pResetRequestList[i].pPendingResetRequest, &commandAcceptance);
- pLynxFWIMData->pResetRequestList[i].inUse = false;
- FWIMCommandIsComplete (pLynxFWIMData->pResetRequestList[i].pPendingResetRequest->fwimCommandID, status);
- break;
- }
- }
-
- // if more than one bus reset request came in during the timer period,
- // complete them with the status from the above LynxFWIMResetBus
- for (i=0;i<kPendingResetRequestsAllowed;i++)
- {
- if (pLynxFWIMData->pResetRequestList[i].inUse)
- {
- pLynxFWIMData->pResetRequestList[i].inUse = false;
- FWIMCommandIsComplete (pLynxFWIMData->pResetRequestList[i].pPendingResetRequest->fwimCommandID, status);
- }
- }
-
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMMiscInterruptDeferredTask
- //
- // This proc deals with miscellaneous interrupts at FireWire deferred task time.
- //
-
- static void LynxFWIMMiscInterruptDeferredTask(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 i;
-
- LynxFWIMDisableVMUserCode(pLynxFWIMData);
-
- // DT no longer scheduled.
- pLynxFWIMData->miscInterruptDTScheduled = false;
-
- i = pLynxFWIMData->miscInterrupt;
- pLynxFWIMData->miscInterrupt = 0;
-
- #ifdef LynxFireBug
- sprintf (fireBug, "LynxFWIM: Interrupts: %s%s%s%s%s%s%s%s%s%s",
- (i & kLynxPHY_TIME_OUT) ? "PHY_TO " : "",
- (i & kLynxIT_STUCK) ? "IT_STUCK " : "",
- (i & kLynxAT_STUCK) ? "AT_STUCK " : "",
- (i & kLynxHDR_ERR) ? "CRC_ERR " : "",
- (i & kLynxTC_ERR) ? "TC_ERR " : "",
- (i & kLynxCYC_LOST) ? "CYC_LOST " : "",
- (i & kLynxCYC_ARB_FAILED) ? "CYC_ARB " : "",
- (i & kLynxITF_UNDER_FLOW) ? "ITF_UF " : "",
- (i & kLynxATF_UNDER_FLOW) ? "ATF_UF " : "",
- (i & kLynxIARB_FAILED) ? "IARB " : "");
- //if (i) LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
- #endif
-
- LynxFWIMEnableVMUserCode(pLynxFWIMData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAckSecondaryInterruptHandler
- //
- // This proc checks the ack received for the sent transaction. If the ack
- // specifies a completed transaction, this proc will complete the transaction.
- // If the ack specifies an error, this proc will retry the transaction.
- //zzz need to handle response pending ack.
- //zzz need locking mechanism between this routine and the timeout routine
- //
- // We aren't called by interrupt, we're called directly by LynxFWIMWrite()
-
- static OSStatus LynxFWIMAckSecondaryInterruptHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- LynxPCLPtr pPCL = (LynxPCLPtr) p2;
- AbsoluteTime timeoutAbsolute;
- UInt32 ackCode, ackType, tryAgain;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMAckSecondaryInterruptHandler");
-
- // Get our internal data.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
- pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
-
- // Make sure pending command is a write.
- if (pFWIMCommandParams->commandType == kFWIMWrite)
- {
- if (status == noErr)
- {
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Check if ack code indicates a completed transfer. Retry if it doesn't.
- if (commandBusy)
- {
- ackCode = (EndianSwap32Bit (pPCL->status) & kLynxAcks) >> kLynxAcksPhase;
- ackType = ((EndianSwap32Bit (pPCL->status) & kLynxAck_Type) != 0);
- tryAgain = 0;
-
- if (ackType == 0) // Normal 1394 ack
- {
- if ((ackCode == kFWAckComplete) || (ackCode == kFWAckPending))
- {
- // This happens the majority of the time.
- //zzz should wait for write response when ack pending
- commandBusy = false;
- }
- else if (ackCode != kFWAckTypeError)
- {
- // This should only be AckDataError, meaning the packet we sent
- // failed CRC at the receiver. However, non-revA parts seem to
- // yield ack 0 in this case. So except for TypeError, just try
- // again. TypeError will probably fail again if we try again,
- // so give up in that case.
- tryAgain = 1;
- }
- else // TypeError
- {
- commandBusy = false;
- status = retryExceededErr; //zzz do we have a better error code?
- }
- }
- else // Some Lynx error code, not a real ack
- {
- if ((ackCode == 0) || (ackCode == 1))
- {
- // 0 indicates retry overrun (too many retries)
- // 1 indicates Link Timeout - meaning nobody home. Assume no Link at that Phy.
- status = retryExceededErr;
- commandBusy = false;
- }
- else if (ackCode == 2)
- {
- // 2 indicates FIFO underrun. This happens sometimes.
- // Just try again.
- // zzz should only retry a limited number of times.
- tryAgain = 1;
- }
- else // unknown ackCode. zzz should retry some of these, needs more study
- {
- status = retryExceededErr;
- commandBusy = false;
- }
- }
- }
-
- if (tryAgain)
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (10 * durationMillisecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMWriteTimer,
- pFWIMAsynchCommandParams,
- &(pLynxFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pLynxFWIMData->requestTimeoutTimerSet = true;
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
- }
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessPacket
- //
- // Dispatch packet processing based on tCode (async or isoch).
- //zzz check destID???
- //
-
- static void LynxFWIMProcessPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 tCode;
- UInt32 ackCode;
- UInt32 pclStatus;
- UInt32 quad0, quad1;
-
- // If we received any packet, then the GRF is not jammed.
- // This will prevent us from suspecting otherwise by mistake.
- pLynxFWIMData->lastARDMA = 0;
-
- // Get first two quads.
- quad0 = ((UInt32 *) packetBuffer)[0];
- quad1 = ((UInt32 *) packetBuffer)[1];
-
- // Compute tCode. If length is zero or first quad is inverse of second quad,
- // set tCode to special self ID tCode.
- if ((packetSize == 0) || (quad0 == ~quad1))
- tCode = kLynxTCodeSelfID;
- else
- tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
-
- if (tCode != kLynxTCodeSelfID)
- {
- pclStatus = EndianSwap32Bit (pPCL->status);
- ackCode = (pclStatus & kLynxAcks) >> kLynxAcksPhase;
- if ((ackCode != 1) && (ackCode != 2))
- {
- tCode = 0x0f; // reserved
-
- //sprintf (fireBug, "LynxFWIM: Whoops, ack %ld in received packet [%08lx]",
- // (long) ackCode, (long) pclStatus);
- //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
- }
- }
-
- // Dispatch processing based on tCode.
- switch (tCode)
- {
- case kFWTCodeWriteQuadlet :
- LynxFWIMProcessWriteQuadletPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeWriteBlock :
- LynxFWIMProcessWriteBlockPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeWriteResponse :
- LynxFWIMProcessWriteResponsePacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadQuadlet :
- LynxFWIMProcessReadQuadletPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadBlock :
- LynxFWIMProcessReadBlockPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadQuadletResponse :
- LynxFWIMProcessReadQuadletResponsePacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadBlockResponse :
- LynxFWIMProcessReadBlockResponsePacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeLock :
- LynxFWIMProcessLockPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeIsochronousBlock :
- LynxFWIMProcessIsochronousBlockPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- case kFWTCodeLockResponse :
- LynxFWIMProcessLockResponsePacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
-
- // This is now a bit different. We don't so much handle the
- // self ID packets as prepare the AsyncRXDT to handle it. We
- // just look at the PHY registers and build up the local self-id
- // and stuff it into the globals. After checking that no additional
- // self-id packets came in then the AsyncRXDT can deal with
- // telling FSL about the packet.
- case kLynxTCodeSelfID :
- LynxFWIMProcessSelfIDPacket
- (pLynxFWIMData, pPCL, packetBuffer, packetSize);
- break;
-
- default :
- LynxFWIMAddAsyncRxPCL (pPCL);
- break;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessSelfIDPacket
- //
- // This proc tries to process a selfID packet.
- //zzz Should validate selfIDs by making sure the phyID is correct , there's
- //zzz enough of them, etc. Need to generate CRC. Should cancel timeout timer.
- //
- // This whole function has a basic race condition. The physical ID in the PHY
- // register is not tied to the self-id packets we recieved. In the case of the
- // older Phys where we always gen the local self-id from the PHY registers we
- // at least know the local self-id packet is correct. What we don't know is
- // whether we got a reset since we last grabbed self-id packets. If we did
- // then the list of external self-id packets may also have a packet for our
- // node ID. The correct set of self-id packets should then be in the PCL.
- //
- // The newer 1394a PHYs complicate the problem further. They include the local
- // self-id packet in the list provided to the link layer. With the current FSL
- // API we need to strip it out. Note that this could be mean stripping out
- // multiple self-id packets if we have more than 3 ports.
- //
- // More complications: Accessing the PHY registers may trigger the dreaded PHY
- // jam problem. To avoid this the best thing would be to use the self-id we
- // stripped from the total set and use that. Problem is this could be from a
- // different node entirely if the PHY register and the self-id list are out
- // of sync.
- //
- // To solve these issues we don't really do much processing of the packets here.
- // Mostly we build up our own self-id packets for the FSL. On newer PHYs this
- // involves removing the self-id from the packetBuffer which is why we still
- // have it here.
-
- static void LynxFWIMProcessSelfIDPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- LynxRegistersPtr pLynxRegs;
- UInt32 localSelfID;
- UInt32 physicalID;
- UInt32 packetPhysID;
- UInt32 gapCount;
- UInt32 speed;
- UInt32 contender;
- UInt32 portStatus;
- UInt32 * sQuad;
- UInt32 localSelfIDSize;
- UInt32 numQuads;
- UInt32 portNum;
- UInt32 portOffset;
- UInt32 packetNum;
- Boolean foundUs;
-
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Build our local selfID.
- //
-
- // FWDebugStr ((ConstStr255Param) "\pSelfID proceeding");
-
- if( pLynxFWIMData->receiveLocalSelfID ) {
-
- // Get physical ID .
-
- physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyPhysicalIDAddress);
- if (physicalID & kLynxExtPhyR)
- pLynxFWIMData->root = true;
- else
- pLynxFWIMData->root = false;
- physicalID = (physicalID & kLynxExtPhyPhysicalID) >> kLynxExtPhyPhysicalIDPhase;
-
- // This will have already been done by the PhyReg primary interrupt handler.
- // But do it again here just to be safe (there is a possible race condition)
-
- // Disable cycle mastering if we're not root.
- if (!pLynxFWIMData->root)
- {
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwap32Bit( kLynxCYCMASTER ));
- }
-
- // Now go find it in the list of self-ids and remove it.
- sQuad = (UInt32 *) packetBuffer;
- foundUs = false;
- numQuads = packetSize >> 2;
-
- while( numQuads ) {
-
- // Only check the quad if it is the first quad in a self-id packet
- if( !( *sQuad & kFWSelfIDPacketType) ) {
- packetPhysID = (*sQuad & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
- if( packetPhysID == physicalID ) {
- foundUs = true;
- break;
- }
- }
- sQuad += 2; // Skip over inverse of node.
- numQuads -= 2;
- }
- if( foundUs ) {
-
- if( pLynxFWIMData->numPHYPorts > 3 )
- localSelfIDSize = 8 * (((pLynxFWIMData->numPHYPorts - 4) >> 3) + 2);
- else
- localSelfIDSize = 8;
- BlockMove( (Ptr) sQuad, &pLynxFWIMData->localSelfIDQuads, localSelfIDSize);
- BlockMove( (Ptr) sQuad + localSelfIDSize, (Ptr) sQuad, ((UInt32) packetBuffer + packetSize) - ((UInt32) sQuad + localSelfIDSize));
- pLynxFWIMData->selfIDPacketSize -= localSelfIDSize;
- }
-
- }
- else {
-
- // Get physical ID and root bit.
- physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPhysicalIDAddress);
- if (physicalID & kLynxPhyR)
- pLynxFWIMData->root = true;
- else
- pLynxFWIMData->root = false;
- physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
- localSelfID = physicalID << kFWSelfIDPhyIDPhase;
-
- // This will have already been done by the PhyReg primary interrupt handler.
- // But do it again here just to be safe (there is a possible race condition)
-
- // Disable cycle mastering if we're not root.
- if (!pLynxFWIMData->root)
- {
- LynxFWIMClearLinkControlBits
- (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
- }
-
- // Get gap count.
- gapCount = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyGCAddress);
- gapCount = (gapCount & kLynxPhyGC) >> kLynxPhyGCPhase;
- localSelfID |= gapCount << kFWSelfID0GapCntPhase;
-
- // Get speed.
- speed = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhySPDAddress);
- speed = (speed & kLynxPhySPD) >> kLynxPhySPDPhase;
- localSelfID |= speed << kFWSelfID0SPPhase;
-
- // Get speed.
- contender = EndianSwap32Bit (pLynxRegs->gpioData[0]);
- if (contender & 1)
- localSelfID |= kFWSelfID0C;
- /*zzz should do it like this. */
- #if 0
- contender = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyCAddress); /* This won't work if the PHY has >3 ports! */
- if (contender & kLynxPhyC)
- localSelfID |= kFWSelfID0C;
- #endif
-
- for( portNum = 0; portNum < 3; portNum++ ) {
-
- // Get port status p0.
- portStatus = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPortStatusAddress + portNum);
- if (portStatus & kLynxPhyCon)
- {
- if (portStatus & kLynxPhyCh)
- localSelfID |= ((kFWSelfIDPortStatusChild << kFWSelfID0P0Phase) >> (portNum << 1));
- else
- localSelfID |= ((kFWSelfIDPortStatusParent << kFWSelfID0P0Phase) >> (portNum << 1));
- }
- else
- {
- localSelfID |= ((kFWSelfIDPortStatusNotConnected << kFWSelfID0P0Phase) >> (portNum << 1));
- }
- }
-
- // Set selfID packet ID, link active, self powered and power class.
- // HardwarePowerClass is a macro from the top of this file.
-
- localSelfID |= ((kFWSelfIDPacketID << kFWPhyPacketIDPhase) |
- kFWSelfID0L |
- (HardwarePowerClass << kFWSelfID0PwrPhase));
-
- // If more than 1 packet, say so
- if( pLynxFWIMData->numPHYPorts > 3 )
- localSelfID |= kFWSelfIDMore;
-
- pLynxFWIMData->localSelfIDQuads[0] = localSelfID;
- pLynxFWIMData->localSelfIDQuads[1] = ~localSelfID;
-
- // Fill in extra self-id packets if necessary.
- packetNum = 0;
- portOffset = 0;
- for( portNum = 3; portNum < pLynxFWIMData->numPHYPorts; portNum++ ) {
- if( portNum == 3 || portNum == 11 || portNum == 19 ) {
-
- // Create quads for previous self-ID packet if necessary
- if( packetNum > 0 ) {
- localSelfID |= kFWSelfIDMore;
- pLynxFWIMData->localSelfIDQuads[packetNum << 1] = localSelfID;
- pLynxFWIMData->localSelfIDQuads[(packetNum << 1) + 1] = ~localSelfID;
- }
- packetNum++;
- portOffset = 0;
- localSelfID = (physicalID << kFWSelfIDPhyIDPhase) |
- (kFWSelfIDPacketID << kFWPhyPacketIDPhase) | kFWSelfIDPacketType |
- ((packetNum - 1) << kFWSelfIDNNPhase);
- }
- portStatus = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPortStatusAddress + portNum);
- if (portStatus & kLynxPhyCon)
- {
- if (portStatus & kLynxPhyCh)
- localSelfID |= ((kFWSelfIDPortStatusChild << kFWSelfIDNPaPhase) >> (portOffset << 1));
- else
- localSelfID |= ((kFWSelfIDPortStatusParent << kFWSelfIDNPaPhase) >> (portOffset << 1));
- }
- else
- {
- localSelfID |= ((kFWSelfIDPortStatusNotConnected << kFWSelfIDNPaPhase) >> (portOffset << 1));
- }
- portOffset++;
- }
- if( packetNum ) {
- pLynxFWIMData->localSelfIDQuads[packetNum << 1] = localSelfID;
- pLynxFWIMData->localSelfIDQuads[(packetNum << 1) + 1] = ~localSelfID;
- }
- }
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessWriteQuadletPacket
- //
- // This proc processes a write quadlet packet.
- //
-
- static void LynxFWIMProcessWriteQuadletPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 pclStatus;
- UInt32 transactionStatus;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteQuadletPacket");
-
- // Get PCL data.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- LynxFWIMProcessWriteQuadletRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);
- pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 3 * sizeof (UInt32));
- pFWIMProcessAsynchParams->length = 4;
- pFWIMProcessAsynchParams->extendedTCode = 0;
-
- pclStatus = EndianSwap32Bit (pPCL->status);
- transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the write request.
- FWProcessWriteRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessWriteQuadletRequestCompletionProc
- //
- // This proc will be called upon completion of write request processing.
- //
-
- static void LynxFWIMProcessWriteQuadletRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- LynxPCLPtr pPCL;
-
- // Get PCL pointer.
- pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessWriteBlockPacket
- //
- // This proc processes a write block packet.
- //
-
- static void LynxFWIMProcessWriteBlockPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 pclStatus;
- UInt32 transactionStatus;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteBlockPacket");
-
- // Get PCL data.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- LynxFWIMProcessWriteBlockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);
- pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- pclStatus = EndianSwap32Bit (pPCL->status);
- transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the write request.
- FWProcessWriteRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessWriteBlockRequestCompletionProc
- //
- // This proc will be called upon completion of write request processing.
- //
-
- static void LynxFWIMProcessWriteBlockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- LynxPCLPtr pPCL;
-
- // Get PCL pointer.
- pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessWriteResponsePacket
- //
- // This proc processes a write quadlet response packet.
- //zzz Verify destinationID, and sourceID.
- //
- // NYI - never tested (never happens? same in TIFWIM)
-
- static void LynxFWIMProcessWriteResponsePacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- #if 0
- LynxRegistersPtr pLynxRegs;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket;
- UInt32 commandType;
- UInt32 tLabel;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr;
- #endif
-
- // FWDebugStr ((ConstStr255Param) "\pNYI LynxFWIMProcessWriteResponsePacket");
- #if 0
- // Get pointer to link registers.
- pLinkRegs = (TILinkRegistersPtr) (pLynxFWIMData->regBaseAddress +
- kTILinkRegistersOffset);
-
- // Read in rest of packet.
- pPacket = (UInt32 *) packetBuffer;
- pPacket++;
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
-
- pPacket = (UInt32 *) packetBuffer;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
-
- // We must have a pending write command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type and transaction label for this packet.
- commandType =
- pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
-
- if ((commandType == kFWIMWrite) &&
- (tLabel == pLynxFWIMData->transactionLabel) &&
- ((pLynxFWIMData->tCode == kFWTCodeWriteQuadlet) ||
- (pLynxFWIMData->tCode == kFWTCodeWriteBlock)))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, noErr);
- }
- }
- }
- #endif
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadQuadletPacket
- //
- // This proc processes a read quadlet packet.
- //
-
- static void LynxFWIMProcessReadQuadletPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 pclStatus;
- UInt32 transactionStatus;
-
- // Get PCL data.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- LynxFWIMProcessReadQuadletRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);//zzz should probably be nil.
- pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 3 * sizeof (UInt32));
- pFWIMProcessAsynchParams->length = 4;
- pFWIMProcessAsynchParams->extendedTCode = 0;
- pclStatus = EndianSwap32Bit (pPCL->status);
-
- pclStatus = EndianSwap32Bit (pPCL->status);
- transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the read request.
- FWProcessReadRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadQuadletRequestCompletionProc
- //
- // This proc will be called upon completion of read request processing.
- //
-
- static void LynxFWIMProcessReadQuadletRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- LynxPCLPtr pPCL;
-
- // Get PCL pointer.
- pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadBlockPacket
- //
- // This proc processes a read block packet.
- //
-
- static void LynxFWIMProcessReadBlockPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 pclStatus;
- UInt32 transactionStatus;
-
- // Get PCL data.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- LynxFWIMProcessReadBlockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz should probably be nil
- pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- pclStatus = EndianSwap32Bit (pPCL->status);
- transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the read request.
- FWProcessReadRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadBlockRequestCompletionProc
- //
- // This proc will be called upon completion of read request processing.
- //
-
- static void LynxFWIMProcessReadBlockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- LynxPCLPtr pPCL;
-
- // Get PCL pointer.
- pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadQuadletResponsePacket
- //
- // This proc processes a read quadlet response packet.
- //zzz Verify destinationID, and sourceID.
- //
-
- static void LynxFWIMProcessReadQuadletResponsePacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 *commandBuffer;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadQuadletResponsePacket");
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
-
- // We must have a pending read command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
- rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
-
- if ((commandType == kFWIMRead) &&
- (tLabel == pLynxFWIMData->transactionLabel) &&
- (pLynxFWIMData->tCode == kFWTCodeReadQuadlet))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- commandBuffer = (UInt32 *) pFWIMAsynchCommandParams->buffer;
- *commandBuffer = pPacket[3];
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessReadBlockResponsePacket
- //
- // This proc processes a read block response packet.
- //zzz Verify destinationID, and sourceID.
- //zzz Must check extended tCode.
- //zzz Must return actual number of bytes transferred.
- //
- // NYI - never tested with Lynx
-
- static void LynxFWIMProcessReadBlockResponsePacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 dataLength;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadBlockResponsePacket");
-
- dataLength = (((UInt32 *) packetBuffer)[3] & kFWAsynchDataLength) >>
- kFWAsynchDataLengthPhase;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
-
- // We must have a pending read command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
- rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
-
- if ((commandType == kFWIMRead) &&
- (tLabel == pLynxFWIMData->transactionLabel) &&
- (pLynxFWIMData->tCode == kFWTCodeReadBlock))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- if (dataLength > pFWIMAsynchCommandParams->length)
- dataLength = pFWIMAsynchCommandParams->length;
- BlockCopy (&(pPacket[4]),
- pFWIMAsynchCommandParams->buffer,
- dataLength);
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessLockPacket
- //
- // This proc processes a lock packet.
- //
-
- static void LynxFWIMProcessLockPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- LynxAsyncRxPCLDataPtr pLynxAsyncRxPCLData;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 pclStatus;
- UInt32 transactionStatus;
-
- // Get PCL data.
- pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- LynxFWIMProcessLockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz receive and transmit buffers should be different
- pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- pclStatus = EndianSwap32Bit (pPCL->status);
- transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the lock request.
- FWProcessLockRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessLockRequestCompletionProc
- //
- // This proc will be called upon completion of lock request processing.
- //
-
- static void LynxFWIMProcessLockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- LynxPCLPtr pPCL;
-
- // Get PCL pointer.
- pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessIsochronousBlockPacket
- //
- // This proc processes an isochronous block packet.
- //zzz Verify destinationID, and sourceID.
- //zzz need to determine which port this packet is for.
- //zzz should break this proc up.
- //zzz data length not accurate if not a multiple of 4.
- //zzz should implement all the synch stuff.
- //
- // Important: We don't service additional packets while the channel handler runs.
- //zzz
- //zzz this code is obsolete and needs to be updated before it will work
- //zzz
-
- static void LynxFWIMProcessIsochronousBlockPacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- /*zzz*/
- #if 0
- /*zzz*/
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams;
- LynxIsochPortDataPtr pLynxIsochPortData;
- DCLCommandPtr pDCLCommand;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 channelNum,
- commandChannelNum;
- UInt32 dataLength;
- Boolean disablePort = false;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessIsochronousBlockPacket");
-
- // Get the pending FWIM command if there is one.
- pFWIMAllocateIsochPortParams = (FWIMAllocateIsochPortParamsPtr)
- &(pLynxFWIMData->fwimAllocateIsochPortParams);
-
- // We must have an active isochronous command and a matching channel number.
- //zzz how do we tell it's active.
- if (pFWIMAllocateIsochPortParams->fwimCommandParams.fwimCommandID !=
- kInvalidFWIMCommandID)
- {
- // Get isoch port data.
- pLynxIsochPortData = (LynxIsochPortDataPtr)
- pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Get pending command type and channel number for this packet.
- commandChannelNum = pFWIMAllocateIsochPortParams->channelNum;
- channelNum = (pPacket[0] & kFWIsochChanNum) >> kFWIsochChanNumPhase;
-
- if (channelNum == commandChannelNum)
- {
- // Get the DCL command.
- pDCLCommand = pLynxFWIMData->pCurrentDCLCommand;
-
- // Compute data length for this buffer.
- dataLength = (((UInt32 *) pPacket)[0] & kFWIsochDataLength) >>
- kFWIsochDataLengthPhase;
- if (dataLength & 0x03)
- dataLength = (dataLength & 0xFFFFFFFC) + 4; // round up to quadwords
-
- // Fill the isoch buffers.
- if (pDCLCommand != nil)
- {
- LynxFWIMRunDCLProgram
- (pLynxIsochPortData, (Ptr) pPacket, dataLength, &pDCLCommand);
- pLynxFWIMData->pCurrentDCLCommand = pDCLCommand;
- }
-
- // If we've run out of buffers, disable port.
- if (pDCLCommand == nil)
- disablePort = true;
- }
- }
-
- // Disable the port if we need to.
- if (disablePort)
- {
-
- // NYI - If we reprogram the DMA comparators, we won't get any more Isoch.
- // Maybe that would be a good idea.
-
- }
-
- /*zzz*/
- #endif
- /*zzz*/
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMProcessLockResponsePacket
- //
- // This proc processes a lock response packet.
- //zzz Verify destinationID, and sourceID.
- //zzz Must check extended tCode.
- //
- // (IRM sends these)
-
- static void LynxFWIMProcessLockResponsePacket(
- LynxFWIMDataPtr pLynxFWIMData,
- LynxPCLPtr pPCL,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 dataLength;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessLockResponsePacket");
-
- dataLength = (pPacket[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase;
- if (dataLength & 0x03)
- dataLength = (dataLength & 0xFFFFFFFC) + 4;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
-
- // We must have a pending lock command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
- rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
-
- if ((commandType == kFWIMLock) &&
- (tLabel == pLynxFWIMData->transactionLabel) &&
- (pLynxFWIMData->tCode == kFWTCodeLock))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- if (dataLength > pFWIMAsynchCommandParams->length)
- dataLength = pFWIMAsynchCommandParams->length;
- BlockCopy (&(pPacket[4]),
- pFWIMAsynchCommandParams->buffer,
- dataLength);
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- LynxFWIMAddAsyncRxPCL (pPCL);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMSetupFIFOs
- //
- // This proc sets up the FIFO sizes and thresholds.
- //zzz this does have safety problems if there's stuff in the FIFOs.
- //
-
- static void LynxFWIMSetupFIFOs(
- LynxFWIMDataPtr pLynxFWIMData)
- {
- LynxRegistersPtr pLynxRegs;
-
- // Get base address for Lynx registers.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
-
- // pause the asynch receiver by disabling comparator, JKL *** should make sure GRF has drained?
- LynxFWIMDisableComparators(pLynxFWIMData);
-
- // Set up FIFOs depending on isochronous transmit mode.
- if (pLynxFWIMData->isochTransmitMode)
- {
- // Flush the FIFOs.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
- (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ) )
- return;
-
- // Raise threshold so stuff won't accidentally go out.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
- (UInt32 ) EndianSwapImm32Bit (0x0000FFFF) ))
- return;
-
- // Set the FIFO sizes.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoSize,
- (UInt32 ) EndianSwapImm32Bit (
- (kIsochTransmitModeITFSize << kLynxITF_FIFOSZPhase) |
- (kIsochTransmitModeATFSize << kLynxATF_FIFOSZPhase) |
- (kIsochTransmitModeGRFSize << kLynxGRF_FIFOSZPhase) ) ))
- return;
-
- // Set the FIFO thresholds.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
- (UInt32 ) EndianSwapImm32Bit (
- (kIsochTransmitModeITFThreshold << kLynxITF_TRSHLDPhase) |
- (kIsochTransmitModeATFThreshold << kLynxATF_TRSHLDPhase) ) ))
- return;
-
- // Flush the FIFOs just to be sure.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
- (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
- return;
- }
- else
- {
- // Flush the FIFOs.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
- (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
- return;
-
- // Raise threshold so stuff won't accidentally go out.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
- (UInt32 ) EndianSwapImm32Bit (0x0000FFFF) ))
- return;
-
- // Set the FIFO sizes.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoSize,
- (UInt32 ) EndianSwapImm32Bit (
- (kDefaultITFSize << kLynxITF_FIFOSZPhase) |
- (kDefaultATFSize << kLynxATF_FIFOSZPhase) |
- (kDefaultGRFSize << kLynxGRF_FIFOSZPhase) ) ))
- return;
-
- // Set the FIFO thresholds.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
- (UInt32 ) EndianSwapImm32Bit (
- (kDefaultITFThreshold << kLynxITF_TRSHLDPhase) |
- (kDefaultATFThreshold << kLynxATF_TRSHLDPhase) ) ))
- return;
-
- // Flush the FIFOs just to be sure.
- if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
- (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
- (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
- return;
- }
-
- // turn asynch comparator back on
- LynxFWIMEnableComparators(pLynxFWIMData);
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWaitForPHYPower
- //
- // Called when we detect that the PHY is not powered. Shuts down the FWIM and
- // sets up a 5 second timer to wait for the PHY to start working again.
- //
- // Shutting down a FWIM involves the following:
- //
- // 1) All outstanding async IOs returned with an error
- // 2) All Interrupts Disabled.
- // 3) All timers canceled.
- // 4) FWIM configured to return errors from all subsequent requests.
- //
- void LynxFWIMWaitForPHYPower(
- LynxFWIMDataPtr pLynxFWIMData,
- Boolean sleepRequest )
- {
- OSStatus status = noErr;
- AbsoluteTime timeoutAbsolute;
- AbsoluteTime timeRemaining;
- LynxRegistersPtr pLynxRegs;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
-
- if( sleepRequest ) {
- // Try to cancel wakeup timer. Do this before checking for
- // already being hosed since we don't want the timer to go
- // off if we are Quiesced
- CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);
- }
-
- // Remember everything is broken
- if( !CompareAndSwap(0,1,(unsigned long *) &pLynxFWIMData->phyNotPowered) )
- return; // Already knew about this problem, nothing to do.
-
- if( !sleepRequest ) {
- // Try to cancel wakeup timer. Do this after checking for
- // already being hosed since we do want the timer to go
- // off if we are in fact PHYless.
- CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);
- }
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
-
- // Try to cancel timeout timer for current command.
- status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID, &timeRemaining);
-
- // Complete command if we didn't already time out.
- if (status == noErr)
- {
- // Finish up command.
-
- if( pLynxFWIMData->pPendingFWIMCommand ) {
- pLynxFWIMData->pPendingFWIMCommand = nil;
- FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, accessErr); // !!! what is the proper error here?!?
- }
- }
-
- // Prevent interrupts from happening so we don't get stuck in some unservicable interrupt loop.
- pLynxRegs = pLynxFWIMData->pLynxRegisters;
- pLynxRegs->pciInterruptEnable = 0;
-
- // If we are here as a result of an FSL sleep request then don't set the wakeup timer
- // and don't pretend we saw a reset.
-
- if( !sleepRequest ) {
-
- // If we have been initialized tell FSL about the reset. If we haven't finished initializing then
- // don't tell FSL about a reset before it is prepared to handle it.
- if( pLynxFWIMData->numPHYPorts ) {
- // Tell FSL a reset happened. This isn't strictly true but we need to tell the FSL something drastic has
- // happened on the bus.
- status = FWProcessBusReset (pLynxFWIMData->fwimID);
- }
-
- // set timer to wake up 5 seconds later and try to wake up the PHY
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (5 * durationSecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMAttemptPHYWakeup,
- pLynxFWIMData,
- &(pLynxFWIMData->phyPowerTimerID));
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMWakeupReset
- //
- // Resets the bus after a delay.
- //
- static OSStatus LynxFWIMWakeupReset(
- void *p1,
- void *p2)
-
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- UInt32 phyReg;
-
- phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
- phyReg |= kLynxPhyIBR;
- LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
-
- return( noErr );
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LynxFWIMAttemptPHYWakeup
- //
- // Tries to wake up the PHY after we detected a no-power situation.
- //
- static OSStatus LynxFWIMAttemptPHYWakeup(
- void *p1,
- void *p2)
- {
- LynxFWIMDataPtr pLynxFWIMData = (LynxFWIMDataPtr) p1;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // Assume for now everything is OK again
- pLynxFWIMData->phyNotPowered = 0;
-
- // If this fails, we'll schedule this task again automatically.
- LynxFWIMFullReset();
-
- // Make sure the bus gets reset since LynxFWIMFullReset only does it when we
- // execute it the first time. Theoretically we just got a reset but we might
- // not have seen it if the PHY was unpowered (and we had ints disabled etc.)
- // To avoid a reset storm we wait a second before issuing the reset
-
- // set timer to reset 1 second later
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationSecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- LynxFWIMWakeupReset,
- pLynxFWIMData,
- &(pLynxFWIMData->phyPowerTimerID));
-
- return( noErr );
-
- }
-
- static void LynxFWIMFireBugMsg (
- LynxFWIMDataPtr pLynxFWIMData,
- char *msg)
- {
- UInt32 sourceID;
-
- if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
- (UInt32 *) &pLynxFWIMData->pLynxRegisters->busNumberNodeNumber,
- (UInt32 *) &sourceID ) )
- return;
-
- sourceID = EndianSwap32Bit( sourceID );
-
- LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_XMT, kFWSpeed100MBit, 4,
- 0x42420010, sourceID, 0x0, (strlen (msg) + 1) << 16,
- strlen (msg) + 1, (UInt32 *) msg);
- }
-
- void LynxFWIMDisableVMUserCode(
- LynxFWIMDataPtr pLynxFWIMData )
- {
-
- FWIMDisableVMUserCode(); // Ordering is important here. We don't want to mark ourselves
- IncrementAtomic(&pLynxFWIMData->fwimBusy); // busy while page faults can happen.
-
-
- }
-
-
- void LynxFWIMEnableVMUserCode(
- LynxFWIMDataPtr pLynxFWIMData)
-
- {
-
- DecrementAtomic(&pLynxFWIMData->fwimBusy); // Ordering is important here. We don't want to allow page faults
- FWIMEnableVMUserCode(); // while we are marked busy.
-
- }
-
-
- /////////////////////////
- // End of LynxFWIM.c //
- /////////////////////////